Hi,

On Wed, Jul 22, 2020 at 1:53 PM Todd Heaps <heaps...@gmail.com> wrote:

> In Wicket 8.3.0, I had to override AsynchronousPageStore to fix a memory
> leak. In looking at older versions of 9.0.0's version
> of AsynchronousPageStore , I thought the memory leak had been fixed, but
> now that 9.0.0 has been released (and maybe it was always that way and I
> wasn't seeing it right), it seems like the memory leak is still there.
>
> Here is 8.3.0's AsynchronousPageStore.PageSavingRunnable inner class with
> the memory leak:
>
>  private class PageSavingRunnable implements Runnable
>  {
>   @Override
>   public void run()
>   {
>    while (pageSavingThread != null)
>    {
>     Entry entry = null;
>     try
>     {
>      entry = entries.poll(POLL_WAIT, TimeUnit.MILLISECONDS);
>     }
>     catch (InterruptedException e)
>     {
>      log.debug("PageSavingRunnable:: Interrupted...");
>     }
>     if (entry != null && pageSavingThread != null)
>     {
>      log.debug("PageSavingRunnable:: Saving asynchronously: {}...", entry);
>      delegate.storePage(entry.sessionId, entry.page);
>      entryMap.remove(getKey(entry));
>     }
>    }
>   }
>  }
>
> Note that in the code above if an exception is thrown during the call:
> delegate.storePage(entry.sessionId, entry.page)
>
> the call:
> entryMap.remove(getKey(entry))
>
> never happens, causing the entryMap to continue to gradually increase in
> size, eventually causing the heap to run out of memory.
>
> I switched those two lines to be:
>      entryMap.remove(getKey(entry));
>      delegate.storePage(entry.sessionId, entry.page);
>
> Now if an exception is thrown in delegate.storePage(), there is no longer a
> problem because the page entry has already been removed.  This has been
> confirmed in our code base where after making the change, we no longer had
> memory leak problems.
>
> Now in Wicket 9.0.0 very similar code looks like it will have the same
> problem. Note the following in AsynchronousPageStore.PageAddingRunnable:
>
>  private static class PageAddingRunnable implements Runnable
>  {
>   private static final Logger log =
> LoggerFactory.getLogger(PageAddingRunnable.class);
>   private final BlockingQueue<PendingAdd> queue;
>   private final ConcurrentMap<String, PendingAdd> map;
>   private final IPageStore delegate;
>   private PageAddingRunnable(IPageStore delegate, BlockingQueue<PendingAdd>
> queue,
>                              ConcurrentMap<String, PendingAdd> map)
>   {
>    this.delegate = delegate;
>    this.queue = queue;
>    this.map = map;
>   }
>   @Override
>   public void run()
>   {
>    while (!Thread.interrupted())
>    {
>     PendingAdd add = null;
>     try
>     {
>      add = queue.poll(POLL_WAIT, TimeUnit.MILLISECONDS);
>     }
>     catch (InterruptedException e)
>     {
>      Thread.currentThread().interrupt();
>     }
>     if (add != null)
>     {
>      log.debug("Saving asynchronously: {}...", add);
>      add.asynchronous = true;
>      delegate.addPage(add, add.page);
>      map.remove(add.getKey());
>     }
>    }
>   }
>  }
>
> If an exception is thrown during the call:
> delegate.addPage(add, add.page);
>
> The call to:
> map.remove(add.getKey());
>
> never happens, which will presumably still cause a memory leak.
>
> We're in the process of migrating from Wicket 8.x to 9.0.0 and will be
> running 9.0.0 in a production environment soon.  If needed, we'll try to
> implement a similar fix for this in 9.0.0,
>
> Do you think this is something that would be important enough to be looked
> into soon?
>

Sure!
Just file a ticket at https://issues.apache.org/jira/browse/WICKET !
You could even send us a Pull Request at https://github.com/apache/wicket with
the change!
Thanks!


> Thanks for your time, and thanks for Wicket.  It's a great web framework.
> We've been using it for many years now.
>
> Todd Heaps
>

Reply via email to