views:

133

answers:

5

Hello all. I have been writing a small java application (my first!), that does only a few things at the moment. Currently, it runs the Main class which launches a gui class (a class I wrote that extends JFrame that only contains a JTextArea), a class that loads a local file through a BufferedInputStream that is approximately 40kb, and class that loads a entry from a Java properties file.

Everything works wonderfully, however, I was watching the Windows task manager and I noticed something that struck me as odd. When I launch the application, the RAM usage jumps to about 40MB while it loads the local file and pulls a few values from it to display in the JTextArea, which seems normal to me because of the JVM, Java base classes, etc. At this point, however, when the application has finished loading the file, itmerely sits idle, as I currently don't have it doing anything else. While it is sitting idle, as long as the window is active, the application's memory usage starts climbing by 10-20kb every second. This strikes me as odd. If I click on another program to make this one the inactive window, the memory still rises, but at a much slower rate (about 10kb every 3-5 seconds).

I have not tested to see how far it would go up, but this strikes me as very odd behavior. Is this normal Java behavior? I guess it is possible that my code could be leaking memory, but I'm not sure how. I did make sure to close the BufferedInputStream I am using, and I can't see what else would cause this.

I'm sorry if my explanation doesn't make sense, but I would appreciate any insight and/or pointers anyone may have.

UPDATE:

Upon suggestion, I basically stripped my application down to the Main class which simply calls the gui class. The gui class only extends JFrame and sets the window size, close operation, and visible properties. With these changes, the memory still grows at 10-20kb, but at a slower rate. This, in conjuction with other advice I have received leads me to believe that this is just Java. I will continue to play with it and let you all know if I find out anything else interesting.

+2  A: 

Congrats on your first app! Now, a couple things to think about. First, the Windows task manager is not a great resource to understand how quickly your vm is growing. Instead, you should monitor your garbage collection stats in the console (use the -verbose:gc commandline param). Second, if you are concerned about potential leaks and the growth of the vm, there are a bunch of great profilers out there that are easy to use and can help you diagnose memory issues. check out these two posts for some profiler options.

akf
@afk, Thanks! I have heard that the Windows Task Manager was not the greatest of tools for monitoring Java apps, but I didn't know how trustworthy that information was. I well check out what you have mentioned.
Jason Watkins
+1  A: 

Congratulations for your first Java app!

Java applications run in a virtual machine. The virtual machine has been assigned a fixed amount of memory by the OS, typically 512 MB. As long as the application uses less than 512 MB the garbage collector won't kick in and start searching for "dead" memory blocks. The JVM memory limit can be modified in most OSes. Try switching the memory limit to 32 MB, for example.

matiasf
@matiasf, thanks!! I will keep this in mind. I am going to try to see how far it actually does rise. Thanks for the suggestions.
Jason Watkins
@matiasf - basically correct, but no JVM that I've come across will allocate an initial heap that big (512Mb) ... unless something specifically tells it to via the JVM launch options.
Stephen C
A: 

Is this normal Java behavior?

No.

I guess it is possible that my code could be leaking memory

That is definitely the cause. Please post your source code, otherwise further diagnosis isn't possible.

I noticed you are using Swing, make sure you are launching your JFrame in the event dispatch thread, using the invokeLater(Runnable) method.

If your are using any sort of collections, make sure you clear them once done.

Since you are doing some file IO, make sure you close all of the classes involved in in the IO operations after you are done with them.

If you are using any event listeners, remember to explicitly remove event listeners when they are no longer necessary.


One thing you could try is experimenting. Take your application and remove the file IO, see what happens. Does the memory usage still climb as before? Now resotre your application to normal, and remove the text area - does the memory still climb as before? Etc, etc. This will help you to determine what the source is, and you can focus your efforts there. Most likely you will uncover what you are after by doing this.

Another useful diagnosis tool is to use System.gc() at particular points in time, usually after the heavy-lifting blocks of code. This will tell the JVM to perform a garbage collection at that point in the execution, rather than at another time determined by memory consumption. This will help you to take into account any periodic fluctuations in the memory usage of your application.

Failing which, you can always use a memory profiler. If you are using Netbeans IDE, there's one built right into it. For Eclipse, there're several plugins which can perform profiling.

bguiz
How is this helpful?
Alastair Pitts
Yes, this is Java. Deal with it.
matiasf
@bguiz I'm not sure I understand what you mean by the event dispatch thread. I am very new to Java and I have not seen that mentioned.
Jason Watkins
@masternosaj : Inside your `public static void main` method, do not instantiate your `JFrame` by calling the constructor. Instead, instantiate it within a `Runnable` and perform an `invokeLater` on the runnable. This is usually for threading, not memory leaks, but it is something you should do anyway, as it is how Sun designed Swing to be used.
bguiz
Good edit, I've amended my vote.
Alastair Pitts
@bguiz, thanks for the tip, I will try that out.
Jason Watkins
+3  A: 

Try monitoring the heap usage with jconsole instead of the Windows task manager:

  • Launch your app with the -Dcom.sun.management.jmxremote option e.g.

java -Dcom.sun.management.jmxremote -jar myapp.jar

  • Launch jconsole from the command line, and connect to the local pid of the java process you started in the last step.
  • Click over to memory and watch heap memory (the default display)

If you watch for a while, you'll probably get a "sawtooth" pattern as the memory climbs over time, but then has sharp drop-offs when the garbage collector runs. You can try to "suggest" garbage collection by clicking the so-labelled button.

When you do this, does the memory usage drop down to the same minimum level, or is the overall minimum increasing over the course of several minutes? If the minimum usage increases, then you have a memory leak. If it always returns to the same minimum level, then you're fine.

Greg Harman
@Greg, this was a very insightful answer. I will give it a try!
Jason Watkins
@Greg, I gave the JConsole a try and it is a pretty nifty utility. As I watched, the heap memory usage kept increasing. When I invoked the GC (with the button you mentioned), memory usage bottomed out. I tried this a few times and it always dropped to about the same minimum level. Thank you so much!
Jason Watkins
Note that JDK 6 has an even niftier utility: JVisualVM. Start it by typing the command `jvisualvm` in a command prompt.
Jesper
@Jesper, I will check that out as well.
Jason Watkins
@Jesper thanks for the pointer - didn't know about that one, but it'll come in handy, as I'm fighting a memory leak issue of my own right now.
Greg Harman
+1  A: 

it is normal. some background calc might leave dead objects around, which JVM isn't in a hurry to clean up. eventually they will be garbage collected, when max mem is approached.

leave your program running overnight, and your machine won't blow up.

irreputable
@irreputable, thanks, I will keep that in mind.
Jason Watkins