ImageJ memory leak?

P

phsamuel

Hi,

I have memory leakage problem using ImagePlus.show() when I use ij
library outside ImageJ. Even after I close the imageplus window, the
memory is not free. I tested the similar situation inside ImageJ and I
don't encounter any memory problem. My test code is attached at the
end. Press the "Show Image" button to show a big image stack. Press the
"show memory usage" to check memory usage. Apparently, no memory is
free after the big image stack is closed...

I am not a very experience Java/ImageJ programmer. Any advice will be
helpful.

samuel

//--------------------------------------------------
package bugReveal;

import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.process.ByteProcessor;

import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JButton;

public class ImagePlusShow extends JFrame {

private JPanel jContentPane = null; // @jve:decl-index=0:
private JButton jButton = null; // @jve:decl-index=0:
private JButton jButton1 = null;

ImagePlus createBigStackImagePlus()
{
ImageStack ims=new ImageStack(640,480);
ByteProcessor bp;
for (int i=0;i<50;i++)
{
bp = new ByteProcessor(640,480);
ims.addSlice("",bp);
}
ImagePlus imp=new ImagePlus("",ims);
return imp;
}

/**
* This method initializes jButton
*
* @return javax.swing.JButton
*/
private JButton getJButton() {
if (jButton == null) {
jButton = new JButton();
jButton.setText("Show Image");
jButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
createBigStackImagePlus().show();
}
});
}
return jButton;
}

/**
* This method initializes jButton1
*
* @return javax.swing.JButton
*/
private JButton getJButton1() {
if (jButton1 == null) {
jButton1 = new JButton();
jButton1.setText("show memory usage");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
System.out.println(IJ.currentMemory());
}
});
}
return jButton1;
}

/**
* @param args
*/
public static void main(String[] args) {
new ImagePlusShow();
}

/**
* This is the default constructor
*/
public ImagePlusShow() {
super();
initialize();
}

/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(300, 200);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
this.pack();
this.setVisible(true);
}

/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJButton(), java.awt.BorderLayout.CENTER);
jContentPane.add(getJButton1(), java.awt.BorderLayout.SOUTH);
}
return jContentPane;
}

}
 
O

Oliver Wong

Hi,

I have memory leakage problem using ImagePlus.show() when I use ij
library outside ImageJ. Even after I close the imageplus window, the
memory is not free. I tested the similar situation inside ImageJ and I
don't encounter any memory problem. My test code is attached at the
end. Press the "Show Image" button to show a big image stack. Press the
"show memory usage" to check memory usage. Apparently, no memory is
free after the big image stack is closed...

[code snipped]

I noticed that you create an ImageStack called "ims", fill it with 50
ByteProcessors, and then throw away the ims. Thus, the ims is available for
garbage collection. I don't know how bit a ByteProcessor is, but 50 doesn't
seem very big to me, which might explain why GC doesn't actually happen. Did
you try running the code with, say, 100'000 ByteProcessors, checking memory
usage, throwing them away, and then generating another 100'000
ByteProcessors and checking memory usage again to see if it has increased
significantly.

AFAIK, you can't directly "force" garbage collection. The only trick I
can think of is to fill up more than half of your memory with
ByteProcessors, then dropping them, then trying to fill up more than half
your memory with ByteProcessors again. The second time you do this, you
wouldn't have enough room unless garbage collection occured (or unless JIT
does some obscure optimizations).

- Oliver
 
R

Roedy Green

AFAIK, you can't directly "force" garbage collection.

you can try System.gc() but that is only a hint. It might be nice
to get a force on that to use for experiments.
 
R

Roedy Green

I have memory leakage problem using ImagePlus.show() when I use ij
library outside ImageJ. Even after I close the imageplus window, the
memory is not free. I tested the similar situation inside ImageJ and I
don't encounter any memory problem. My test code is attached at the
end. Press the "Show Image" button to show a big image stack. Press the
"show memory usage" to check memory usage. Apparently, no memory is
free after the big image stack is closed...

You likely don't have a leak, but rather packratting -- where you hold
onto old objects you no longer need. See
http://mindprod.com/jgloss/packratting.html

To track down just what the problem is, you want to know what kinds of
objects are plugging RAM . see
http://mindprod.com/jgloss/profiler.html
 
P

phsamuel

Thanks a lot for the advice. I tried System.gc() but the problem
persists. I'll try more and probably send an email to the author of
ImageJ. The weird thing is that I have no problem at all if I run
inside ImageJ as a plugin. It only needs minimal modification and is
shown below.

samuel

//------------------------------------
import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.process.ByteProcessor;
import ij.plugin.*;

import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JButton;

public class ImagePlusShow_memory_check extends JFrame implements
PlugIn {

private JPanel jContentPane = null; // @jve:decl-index=0:
private JButton jButton = null; // @jve:decl-index=0:
private JButton jButton1 = null;

ImagePlus createBigStackImagePlus()
{
ImageStack ims=new ImageStack(640,480);
ByteProcessor bp;
for (int i=0;i<50;i++)
{
bp = new ByteProcessor(640,480);
ims.addSlice("",bp);
}
ImagePlus imp=new ImagePlus("",ims);
return imp;
}

/**
* This method initializes jButton
*
* @return javax.swing.JButton
*/
private JButton getJButton() {
if (jButton == null) {
jButton = new JButton();
jButton.setText("Show Image");
jButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
createBigStackImagePlus().show();
}
});
}
return jButton;
}

/**
* This method initializes jButton1
*
* @return javax.swing.JButton
*/
private JButton getJButton1() {
if (jButton1 == null) {
jButton1 = new JButton();
jButton1.setText("show memory usage");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
IJ.freeMemory();
System.out.println(IJ.currentMemory());
}
});
}
return jButton1;
}


public void run(String arg) {
}

/**
* This is the default constructor
*/
public ImagePlusShow_memory_check() {
super();
initialize();
}

/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(300, 200);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
this.pack();
this.setVisible(true);
}

/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJButton(), java.awt.BorderLayout.CENTER);
jContentPane.add(getJButton1(), java.awt.BorderLayout.SOUTH);
}
return jContentPane;
}

}
 
O

Oliver Wong

Thanks a lot for the advice. I tried System.gc() but the problem
persists.

As I said earlier, there is direct way to force a garbage collection.
Roedy mentioned System.gc(), but with the caveat that it is only a
suggestion to the runtime to start garbage collection; not a mandatory
command to do so.
I'll try more and probably send an email to the author of
ImageJ. The weird thing is that I have no problem at all if I run
inside ImageJ as a plugin. It only needs minimal modification and is
shown below.

As I said earlier, your test only creates 50 objects. Maybe the runtime
feels that the amount of memory used up by these objects is so negligeable
as to not require wasting time with garbage collection. This is why I
recommended you try to exaust your system memory by taking up, say 75% of
it, then discarding all those objects, then allocating another 75% of your
memory, to force a garbage collection to occur.

- Oliver
 
P

phsamuel

I tried what you suggested already. 50 objects are actually pretty big.
It used 15M. If I clicked "show image" three times. It already used up
75% of the memory. The default memory allocation seems to be around
60M. The application crashes when I click the fourth time...

samuel
 
O

Oliver Wong

I tried what you suggested already. 50 objects are actually pretty big.
It used 15M. If I clicked "show image" three times. It already used up
75% of the memory. The default memory allocation seems to be around
60M. The application crashes when I click the fourth time...

Okay, thank you. What does ImagePlus.show() do? Display the image in a
new frame? If so, when you close the window, do you need to dipose it
somehow? If ImagePlus extends JFrame, you might need to call
setDefaultCloseOperation(DISPOSE_ON_CLOSE) on it.

- Oliver
 
R

Roedy Green

import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.process.ByteProcessor;
import ij.plugin.*;

It hard to help you since we don't have this code and are not familiar
with how it works.

I noticed this little piece, not directly your problem, but a problem
nonetheless with all your code:

*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane()
{
if ( jContentPane == null )
{
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJButton(), java.awt.BorderLayout.CENTER);
jContentPane.add(getJButton1(), java.awt.BorderLayout.SOUTH);
}
return jContentPane;
}

}


Get implies simply fetching some value that already exists. I would
called that "buildStrawberryPanel" which is more indicative of what it
really does.

Also you have used a word "ContentPane" that has very specific meaning
in a nonstandard way. This is extremely confusing.

Instead of jContentPane call that variable the wombatPanel or
whatever it is.

Use names that mean something not, generic words like button1 and
button2 untess the buttons are literally labelled 1 and 2.
 
C

Chris Smith

Roedy Green said:
private JPanel getJContentPane()
{
if ( jContentPane == null )
{
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJButton(), java.awt.BorderLayout.CENTER);
jContentPane.add(getJButton1(), java.awt.BorderLayout.SOUTH);
}
return jContentPane;
}


Get implies simply fetching some value that already exists. I would
called that "buildStrawberryPanel" which is more indicative of what it
really does.

I don't see a problem, on the other hand. This is a straight-forward
implementation of lazy initialization (assuming that multithreading is
not a requirement), and follows all the standard conventions of a lazy-
initialization accessor.

Note that after the very first time it's called, it no longer builds
anything.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top