Java Forum / General / September 2005
ImageJ memory leak?
phsamuel@gmail.com - 15 Sep 2005 19:49 GMT 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; } }
Oliver Wong - 15 Sep 2005 20:16 GMT > Hi, > [quoted text clipped - 5 lines] > "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
Roedy Green - 15 Sep 2005 22:06 GMT > 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.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
Roedy Green - 16 Sep 2005 03:10 GMT >I have memory leakage problem using ImagePlus.show() when I use ij >library outside ImageJ. Even after I close the imageplus window, the [quoted text clipped - 3 lines] >"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
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
phsamuel@gmail.com - 16 Sep 2005 04:44 GMT 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; } }
Oliver Wong - 16 Sep 2005 15:38 GMT > 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
phsamuel@gmail.com - 16 Sep 2005 17:36 GMT 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
Oliver Wong - 16 Sep 2005 17:47 GMT >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
Roedy Green - 18 Sep 2005 06:47 GMT >Thanks a lot for the advice. I tried System.gc() but the problem >persists. Of course the error persisted. Java does not give you an out of memory error until it has exhausted gc.
see http://mindprod.com/runerrormessages.html#OUTOFMEMORYERROR
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
Roedy Green - 18 Sep 2005 07:02 GMT >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.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
Chris Smith - 18 Sep 2005 15:36 GMT > private JPanel getJContentPane() > { [quoted text clipped - 11 lines] > 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.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|