[ 
https://issues.apache.org/jira/browse/WICKET-2384?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12734035#action_12734035
 ] 

Tsutomu YANO commented on WICKET-2384:
--------------------------------------

OK. my problem is solved with your fixed code. 
Thank you.

> OutOfMemoryError occur for memory leak on FeedbackPanel & FeedbackMessages
> --------------------------------------------------------------------------
>
>                 Key: WICKET-2384
>                 URL: https://issues.apache.org/jira/browse/WICKET-2384
>             Project: Wicket
>          Issue Type: Bug
>          Components: wicket
>    Affects Versions: 1.3.6, 1.4-RC7
>         Environment: reproduceable on wicket-1.4-rc7(current newest) and 
> wicket-1.3.6(current newest release of 1.3 series). tested on Windows XP and 
> Mac OS X
>            Reporter: Tsutomu YANO
>            Assignee: Igor Vaynberg
>            Priority: Critical
>             Fix For: 1.3.8, 1.4.1
>
>         Attachments: wickettestapp.tar.gz
>
>
> When I uses component.info() method to display a message, my program stopped 
> by OutOfMemoryError or StackOverflowError. 
> I create a sample application to show this problem. Open attached tar.gz 
> file(including a maven project) and run. 
> check 'submit continuously' checkbox and click 'register' button. 
> The program will display current session size continuously on console. the 
> size will be increased, and finally program will be 
> stopped with OutOfMemoryError or StackOverflowError. 
> But if you changes only one line, this program will not be stopped. 
> ---original code--- 
>     private SubmitLink insertLink = new SubmitLink("insertLink") { 
>         public void onSubmit() { 
>             info("message"); 
>             setResponsePage(new Test(testFormBean)); 
>             Session session = Session.get(); 
>             long size = session.getSizeInBytes(); 
>             LOGGER.info("SESSION SIZE: {}", size); 
>         } 
>     }; 
> --------------------- 
> ---changed---------- 
>     private SubmitLink insertLink = new SubmitLink("insertLink") { 
>         public void onSubmit() { 
>             Session.get().info("message");  //CHANGED!!! 
>             setResponsePage(new Test(testFormBean)); 
>             Session session = Session.get(); 
>             long size = session.getSizeInBytes(); 
>             LOGGER.info("SESSION SIZE: {}", size); 
>         } 
>     }; 
> -------------------- 
>    so component's info() method is the reason of this problem. If you 
> commented out 'info()' line, this program never crashed.
>    We found out the reason of this problem in a static inner class 
> 'MessageListView' in FeedbackPanel.
>   MessageListView uses annonimous inner class of Model (named ad 
> 'replacementModel'), and it imports a FeedbackMessage object from 
> enclosing instance. FeedbackPanel holds this annonimous inner class and the 
> annonimous inner class holds a FeedbackMessage.
>   When we use component's info() method, the component is assigned into 
> FeedbackMessage object as a 'reporter' object. so, all of 
> FeedbackMessage objects have a component instance inside of himself as 
> 'reporter' (only one exception: if you use Session.get().info() 
> method instead of component's info() method, 'reporter' object become null).
>   All already-displayed FeedbackMessages will be purged at 'detach' time from 
> Session object. But FeedbackPanel holds FeedbackMessages. 
> So when page is serialized, all FeedbackMessages, all 'reporter' components 
> is serialized. This is the reason of this problem.
>   We can solve this problem if we do not hold FeedbackMessage instance in the 
> annnonimous inner class.
> change the code of FeedbackPanel as bellow (this code is based on 
> FeedbackPanel class of wicket 1.4-rc7, line 70):
> ---- original code -----
> @Override
> protected void populateItem(final ListItem<FeedbackMessage> listItem)
> {
>     final FeedbackMessage message = listItem.getModelObject();
>     message.markRendered();
>     final IModel<String> replacementModel = new Model<String>()
>     {
>         private static final long serialVersionUID = 1L;
>         /**
>          * Returns feedbackPanel + the message level, eg 
> 'feedbackPanelERROR'. This is used
>          * as the class of the li / span elements.
>          * 
>          * @see org.apache.wicket.model.IModel#getObject()
>          */
>         @Override
>         public String getObject()
>         {
>             return getCSSClass(message);
>         }
>     };
>     final Component label = newMessageDisplayComponent("message", message);
>     final AttributeModifier levelModifier = new AttributeModifier("class", 
> replacementModel);
>     label.add(levelModifier);
>     listItem.add(levelModifier);
>     listItem.add(label);
> }
> --------------------
> ---- fixed code ----
> @Override
> protected void populateItem(final ListItem<FeedbackMessage> listItem)
> {
>     //FIXED message must not be 'final'. It must not be used in inner class.
>     //If message could be used in inner class, the instance could be hold by
>     //inner class tacitly and never cleared at detach time and will be 
> serialized.
>     FeedbackMessage message = listItem.getModelObject();
>     message.markRendered();
>     final IModel<String> replacementModel = new Model<String>()
>     {
>         private static final long serialVersionUID = 1L;
>         /**
>          * Returns feedbackPanel + the message level, eg 
> 'feedbackPanelERROR'. This is used
>          * as the class of the li / span elements.
>          * 
>          * @see org.apache.wicket.model.IModel#getObject()
>          */
>         @Override
>         public String getObject()
>         {
>             //FIXED -- retrieve a FeedbackMessage object from ListView's 
> Model.
>             //         never hold it.
>             @SuppressWarnings("unchecked")
>             List<FeedbackMessage> list = (List<FeedbackMessage>) 
> MessageListView.this.getDefaultModelObject();
>             FeedbackMessage feedbackMessage = null;
>             int index = listItem.getIndex();
>             if(index < list.size()) {
>                 feedbackMessage = list.get(index);
>             }
>             if(feedbackMessage == null) return "";
>             return getCSSClass(feedbackMessage);
>             //UNTIL HERE
>         }
>     };
>     final Component label = newMessageDisplayComponent("message", message);
>     final AttributeModifier levelModifier = new AttributeModifier("class", 
> replacementModel);
>     label.add(levelModifier);
>     listItem.add(levelModifier);
>     listItem.add(label);
> }
> --------------------

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to