Memory leak with GLJPanel

Hello all,

I found an always-reproducable memory leak with GLJPanel but I do not know where I can report the bug… Hopefully, somebody here will tell me where the JOGL’s bug database resides!

The memory leak happens everytime a GLJPanel is detached from the components arborescence. For instance, if a GLJPanel is added in a JFrame, when calling removeAll() on that JFrame, the GLJPanel is still indirectly held by the following reference chain:


-> java.awt.EventDispatchThread@0x9501d788 (117 bytes)  (field threadLocals:)
--> java.lang.ThreadLocal$ThreadLocalMap@0x9501f718 (20 bytes) (field table:)
--> [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0x9501f730 (72 bytes) (Element 5 of [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0x9501f730:)
--> java.lang.ThreadLocal$ThreadLocalMap$Entry@0x9501f7e0 (28 bytes) (field value:)
--> com.sun.opengl.impl.GLPbufferImpl$InitAction@0x9503f880 (12 bytes) (field this$0:)
--> com.sun.opengl.impl.GLPbufferImpl@0x9503f890 (48 bytes) (field drawableHelper:)
--> com.sun.opengl.impl.GLDrawableHelper@0x950476c0 (13 bytes) (field listeners:)
--> java.util.ArrayList@0x950476d0 (20 bytes) (field elementData:)
--> [Ljava.lang.Object;@0x950476e8 (12 bytes) (Element 0 of [Ljava.lang.Object;@0x950476e8:)
--> javax.media.opengl.GLJPanel$Updater@0x950476f8 (16 bytes) (field this$0:)
--> GLJPanel@0x95047888 (514 bytes)

It appears that the GLPbufferImpl$InitAction is never released. Since it is a non-static nested class, it maintains the GLPbufferImpl in memory and then, the GLJPanel through a chain of event listeners.

I reproduced the bug with a simple application: it shows a JFrame that contains either a GLJPanel or a JPanel or both. Two menu entries allow to separately add or remove the GLJPanel and the JPanel from the JFrame’s arborescence. By using jmap and jhat utilities (or any other memory profiler), one can verify that when the JPanel is removed, it properly becomes eligible for garbage collection but when the GLJPanel is removed, it is still held by the same reference chain than described above. In that application, the JPanel is shown in green and the GLJPanel will certainly appear black since it does not display any OpenGL scene.

Here is the code of my small application:


import java.awt.Color;
import java.awt.event.ActionEvent;

import javax.media.opengl.GLJPanel;
import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;

public class Program
{
	public static void main(final String[] args)
	{
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}

	static Frame frame = new Frame();
}

class Frame extends JFrame
{
	private static final long serialVersionUID = 1L;

	private boolean isPanelVisible = true;

	private boolean isGLPanelVisible = true;

	public Frame()
	{
		JMenuBar menuBar = new JMenuBar();
		JMenu menu = new JMenu("Menu");
		menuBar.add(menu);
		menu.add(new ShowPanelAction());
		menu.add(new ShowGLPanelAction());

		this.setJMenuBar(menuBar);

		this.setSize(400, 200);

		this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.X_AXIS));
		this.update();
	}

	void changePanelVisibility()
	{
		this.isPanelVisible = !this.isPanelVisible;
		this.update();
	}

	void changeGLPanelVisibility()
	{
		this.isGLPanelVisible = !this.isGLPanelVisible;
		this.update();
	}

	private void update()
	{
		this.getContentPane().removeAll();

		if (this.isPanelVisible)
		{
			this.add(new Panel());
		}
		if (this.isGLPanelVisible)
		{
			this.add(new GLPanel());
		}

		this.validate();
		this.repaint();
	}
}

class ShowPanelAction extends AbstractAction
{
	private static final long serialVersionUID = 1L;

	public ShowPanelAction()
	{
		super("Show/Hide JPanel");
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		Program.frame.changePanelVisibility();
	}
}

class ShowGLPanelAction extends AbstractAction
{
	private static final long serialVersionUID = 1L;

	public ShowGLPanelAction()
	{
		super("Show/Hide GLJPanel");
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		Program.frame.changeGLPanelVisibility();
	}
}

class Panel extends JPanel
{
	private static final long serialVersionUID = 1L;

	public Panel()
	{
		this.setBackground(Color.green);
	}
}

class GLPanel extends GLJPanel
{
	private static final long serialVersionUID = 1L;
}

I run a Debian linux box with Jogl 1.1.1.

Any help that tell me how I could report this bug in the right place would be greatly appreciated.

Many thanks!
Cyrille

I would just like to add that I have noticed a similar memory leak running jogl 1.1.1 under Debian Linux. When using PBuffers for rendering a sequence of offscreen images (one pbuffer per image), the memory usage rises steadily although I call pbuffer.destroy() after each rendering call. When I hack the code to always use the same pbuffer there is no such memory usage increase.

Hi!

You can submit a bug report here:
https://jogl.dev.java.net/servlets/ProjectIssues