Uploaded image for project: 'Wicket'
  1. Wicket
  2. WICKET-2384

OutOfMemoryError occur for memory leak on FeedbackPanel & FeedbackMessages

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Critical
    • Resolution: Fixed
    • 1.3.6, 1.4-RC7
    • 1.3.7, 1.4.0
    • wicket
    • None
    • 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

    Description

      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()
        Unknown macro: { //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);
      }
      --------------------

      Attachments

        1. wickettestapp.tar.gz
          5 kB
          Tsutomu YANO

        Activity

          People

            ivaynberg Igor Vaynberg
            t_yano Tsutomu YANO
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: