You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by "Matej Knopp (JIRA)" <ji...@apache.org> on 2009/07/21 19:04:15 UTC

[jira] Commented: (WICKET-2384) OutOfMemoryError occur for memory leak on FeedbackPanel & FeedbackMessages

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

Matej Knopp commented on WICKET-2384:
-------------------------------------

Problem is that we keep reference to FeedbackMessage in component inside MessageListView item. The feedback message references previous page - that causes the problem, because the previous page is serialized together with current (and the page before, etc). 

Simply removing components from MessageListView should fix the problem.

class MessageListView
{
  ...
  @Override 
  protected void onDetach()
  {
    removeAll();
    super.onDetach();
  }

}

> 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
>            Priority: Critical
>         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.