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

[jira] Updated: (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:all-tabpanel ]

Tsutomu YANO updated WICKET-2384:
---------------------------------

    Attachment: wickettestapp.tar.gz

sample application to reproduce this problem.

> 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. 
> on both of wicket 1.4-rc7 and wicket 1.3.6.
> 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.