2012-08-29 26 views
6

हमारे JavaEE6 परियोजना (EJB3, JSF2) में JBoss 7.1.1 पर, ऐसा लगता है हम SeamFaces @ViewScoped साथ एक स्मृति रिसाव है।ViewScoped बीन के साथ मेमोरी रिसाव?

हम इस तथ्य की जांच करने के लिए एक छोटे प्रोटोटाइप बनाया:

  • हम JMeter का प्रयोग कर एक पेज 200 गुना कॉल करने के लिए;
  • पृष्ठ में एक दृश्यमान बीन है जो एक राज्यव्यापी ईजेबी इंजेक्ट करता है;
  • हम सत्र टाइमआउट को 1 मिनट पर ठीक करते हैं।

परीक्षण, हम VisualVM के साथ स्मृति की सामग्री की जांच, और यहाँ के अंत हम क्या मिला पर:

    एक @ViewScoped सेम के साथ
  • , हम अभी भी स्टेटफुल MyController की 200 उदाहरणों मिल - और @PreDestroy विधि कभी नहीं कहा जाता है;
  • @ConversationScoped बीन, @preDestroy विधि को सत्र अंत कहा जाता है और फिर हमें एक साफ़ स्मृति मिलती है।

क्या हम दृश्यमान क्षेत्र का बुरी तरह से उपयोग करते हैं, या यह वास्तव में एक बग है?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:s="http://jboss.org/seam/faces"> 
    <f:metadata> 
     <f:viewParam name="u" value="#{myBean.uselessParam}" /> 
     <s:viewAction action="#{myBean.callService}" /> 
    </f:metadata> 
    <h:body > 
     <f:view> 
     </f:view> 
    </h:body>  
</html> 

अब शामिल सेम myBean:


यहाँ एक्सएचटीएमएल पृष्ठ है। @ConversationScoped संस्करण के लिए, सभी टिप्पणी किए गए भाग असम्बद्ध हैं।

@ViewScoped 
// @ConversationScoped 
@Named 
public class MyBean implements Serializable 
{ 
    @Inject 
    MyController myController; 
    //@Inject 
    //Conversation conversation; 

    private String uselessParam; 

    public void callService() 
    { 
     //if(conversation.isTransient()) 
     //{ 
     //   conversation.begin(); 
     //} 
     myController.call(); 
    } 

    public String getUselessParam() 
    { 
     return uselessParam; 
    } 

    public void setUselessParam(String uselessParam) 
    { 
     this.uselessParam = uselessParam; 
    } 
} 

और फिर इंजेक्शन स्टेटफुल सेम MyController:

@Stateful 
@LocalBean 
public class MyController 
{ 
    public void call() 
    { 
     System.out.println("call "); 
    } 

    @PreDestroy 
    public void destroy() 
    { 
     System.out.println("Destroy"); 
    } 
} 

उत्तर

5

मुझे लगता है कि कई डेवलपर @ViewAccessScoped Myface CODI से संतुष्ट हैं। क्या आप इसे आज़मा सकते हैं और प्रतिक्रिया दे सकते हैं।

+2

हमने सीओडीआई के साथ प्रयास किया और परीक्षण अच्छी तरह से चला गया। अच्छा! –

3

काफी संभावनाएँ हैं यह एक बग है। ईमानदारी से सीम 3 कार्यान्वयन इतना अच्छा नहीं था और सीओडीआई (और डेल्टास्पीक में भी क्या होगा) बहुत बेहतर है।

5

मुझे जेएसएफ प्रबंधित @ViewScoped बीन में उपर्युक्त समस्या का सामना करना पड़ा है। कुछ ब्लॉगों का जिक्र करने के बाद मुझे समझ में आया कि जेएसएफ http सत्र में बीन राज्यों को देखता है और सत्र को अमान्य होने पर ही नष्ट हो जाता है। जब भी हम जेएसएफ पेज पर क्लिक करते हैं, हर बार नए दृश्य स्कोप बीन पृष्ठ में संदर्भित किया जाता है। मैंने स्प्रिंग कस्टम व्यू स्कोप का उपयोग करके एक काम किया। यह बढ़िया काम करता है। नीचे विस्तार कोड है।

JSF 2.1 के लिए:

चरण 1: एक दृश्य स्कोप बीन पोस्ट का निर्माण श्रोता के रूप में निम्नानुसार बनाएँ।

public class ViewScopeBeanConstructListener implements ViewMapListener { 

    @SuppressWarnings("unchecked") 
    @Override 
    public void processEvent(SystemEvent event) throws AbortProcessingException { 
     if (event instanceof PostConstructViewMapEvent) { 
      PostConstructViewMapEvent viewMapEvent = (PostConstructViewMapEvent) event; 
      UIViewRoot viewRoot = (UIViewRoot) viewMapEvent.getComponent(); 
      List<Map<String, Object>> activeViews = (List<Map<String, Object>>) 
       FacesContext.getCurrentInstance().getExternalContext().getSessionMap(). get("com.org.jsf.activeViewMaps"); 
      if (activeViews == null) { 
       activeViews = new ArrayList<Map<String, Object>>(); 
       activeViews.add(viewRoot.getViewMap()); 
       FacesContext.getCurrentInstance().getExternalContext().getSessionMap(). put("com.org.jsf.activeViewMaps", activeViews); 
      } else { 
       activeViews.add(viewRoot.getViewMap()); 
      } 
     } 
    } 

चरण 2: चेहरे-कॉन्फ़िगरेशन में ईवेंट श्रोता पंजीकृत करें।xml

<system-event-listener> 
    <system-event-listener-class> 
     com.org.framework.custom.scope.ViewScopeBeanConstructListener 
    </system-event-listener-class> 
    <system-event-class>javax.faces.event.PostConstructViewMapEvent</system-event-class> 
    <source-class>javax.faces.component.UIViewRoot</source-class> 
</system-event-listener> 

चरण 3: निम्नानुसार कस्टम व्यू स्कोप बीन बनाएं।

public class ViewScope implements Scope { 

    @Override 
    public Object get(String name, ObjectFactory objectFactory) { 
     Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
      if (viewMap.containsKey(name)) { 
        return viewMap.get(name); 
      } else { 
       List<Map<String, Object>> activeViewMaps = (List<Map<String, Object>>) 
       FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("com.org.jsf.activeViewMaps"); 
       if (activeViewMaps != null && !activeViewMaps.isEmpty() 
        && activeViewMaps.size() > 1) { 
         Iterator iterator = activeViewMaps.iterator(); 
        if (iterator.hasNext()) { 
          Map<String, Object> oldViewMap = (Map<String, Object>) 
          iterator.next(); 
          oldViewMap.clear(); 
          iterator.remove(); 
        } 
        } 
       Object object = objectFactory.getObject(); 
       viewMap.put(name, object); 
       return object; 
      } 

    } 

नोट: अन्य ओवरराइड विधियां खाली हो सकती हैं।

JSF 2.2 के लिए:

JSF 2.2 कुंजी के रूप में 'com.Sun.faces.application.view.activeViewMaps' में http सत्र में नेविगेट नक्शे देखें बचाता है। तो वसंत कस्टम व्यू स्कोप में नीचे कोड जोड़ें। जेएसएफ 2.1

public class ViewScope implements Scope { 

    public Object get(String name, ObjectFactory objectFactory) { 
     Map<String, Object> viewMap = 
      FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
       if (viewMap.containsKey(name)) { 
        return viewMap.get(name); 
       } else { 
         LRUMap lruMap = (LRUMap) FacesContext.getCurrentInstance(). 
    getExternalContext().getSessionMap().get("com.sun.faces.application.view.activeViewMaps"); 
       if (lruMap != null && !lruMap.isEmpty() && lruMap.size() > 1) { 
        Iterator itr = lruMap.entrySet().iterator(); 
        while (itr.hasNext()) {//Not req 
        Entry entry = (Entry) itr.next(); 
        Map<String, Object> map = (Map<String, Object>) entry.getValue(); 
        map.clear(); 
        itr.remove(); 
        break; 
        } 
       } 
       Object object = objectFactory.getObject(); 
       viewMap.put(name, object); 
       return object; 
     } 
} 
+0

क्या आप कृपया अपने कोड में एलआरयूएमएपी और दूसरों के लिए आयात साझा कर सकते हैं? चुनने के लिए कई आयात विकल्प हैं और यह वर्तमान में विफल रहा है। – user1746582

+0

हाय @ सतीश कुमार, मुझे पता है कि यह इस पोस्ट को काफी पुराना है। लेकिन अगर आप मुझे उसी मुद्दे के साथ मार्गदर्शन कर रहे हैं तो यह वास्तव में सहायक होगा। मैं सार्वजनिक ऑब्जेक्ट को ओवरराइड करने में सक्षम नहीं हूं (स्ट्रिंग नाम, ऑब्जेक्ट फैक्ट्री ऑब्जेक्ट फैक्ट्री)। मुझे विधि मिल रही है TypeVariable लुकअप (स्ट्रिंग नाम)। मैं जेएसएफ-एपीआई संस्करण 2.1.3 का उपयोग कर रहा हूं। क्या आप कृपया मेरी मदद कर सकते हैं। –

संबंधित मुद्दे