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.