[
https://issues.apache.org/jira/browse/WICKET-2384?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Igor Vaynberg updated WICKET-2384:
----------------------------------
Fix Version/s: 1.3.8
> 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.0
>
> 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.