views:

101

answers:

5

I have been developing a small Java utility that uses two frameworks: Encog and Jetty to provide neural network functionality for a website.

The code is 'finished' in that it does everything it needs to do, but I have some problems with memory usage. When running on my development machine the memory usage seems to fluctuate between about 4MB and 13MB when the application is doing things (training neural networks) and at most it uses about 18MB. This is very good usage and I think it is due to the fact that I call System.GC() fairly regularly. I do this because the processing time doesn't matter for me, but the memory usage does.

So it all works fine on my machine, but as soon as I put it online on our server (shared unix hosting with memory limits) it uses about 19MB to start with and rises to hundreds of MB of memory usage when doing things. These are the same things that I have been doing in testing. The only way, I believe, to reduce the memory usage, is to quit the application and restart it.

The only difference that I can tell is the Java Virtual Machine that it is being run on. I do not know about this and I have tried to find the reason why it is acting this way, but a lot of the documentation assumes a great knowledge of Java and Virtual Machines. Could someone please help m with some reasons why this may be happening and perhaps some things to try to stop it.

I have looked at using GCJ to compile the application, but I don't know if this is something I should be putting a lot of time in to and whether it will actually help.

Thanks for the help!

  • UPDATE: Developing on Mac OS 10.6.3 and server is on a unix OS but I don't know what. (Server is from WebFaction)
+7  A: 

I think it is due to the fact that I call System.GC() fairly regularly

You should not do that, it's almost never useful.

A garbage collector works most efficiently when it has lots of memory to play with, so it will tend to use a large part of what it can get. I think all you need to do is to set the max heap size to something like 32MB with an -Xmx32m command line parameter - the default depends on whether the JVM believes it's running on a "server class" system, in which case it assumes that you want the application to use as much memory as it can in order to give better throughput.

BTW, if you're running on a 64 bit JVM on the server, it will legitimately need more memory (usually about 30%) than on a 32bit JVM due to larger references.

Michael Borgwardt
Ideally, the RAM usage can't go over 40MB. That is about what I have to play with for this application on the server. I assume the server is 64 bit but is it possible/advisable to force it to use a 32 bit VM?When I said the RAM usage fluctuates between 4 and 13MB in testing, I believe the usage drops from 13 to about 4 every time I call System.GC() but I don't know for sure.
danpalmer
So put -Xmx40m -Xms40m and your program will always use exactly 40M of ram. Then remove all calls to System.gc, as that is poor Java style. The JVM will deal with GC for you, just give it the bounds of memory it has to play with (as I suggested above)
bwawok
Ok, thanks, I will try this. I didn't think that System.GC() was a good idea. Having done a bit of C#, I would never do it in that and it seemed like a 'hack' when I did it in Java, but it seemed to help. I will have a go with these ideas and report back.
danpalmer
Since java 6u14 the 64 bit vm has a really cool feature named "Compressed Object Pointers", on heap sizes < 32GB a reference will still only use 32 bits. Details are at http://java.sun.com/javase/6/webnotes/6u14.html and http://wikis.sun.com/display/HotSpotInternals/CompressedOops
Jörn Horstmann
@Jörn, have you used this facility in production yet?
Thorbjørn Ravn Andersen
@Thorbjørn: No, haven't used it in production. Just found it fascinating that some low-level optimizations can be done transparently on managed runtimes which would be rather difficult in statically compiled programs.
Jörn Horstmann
Thanks for the tips everyone. This answer was the first to mention some of the problems even if several people mentioned them so I have accepted this one, but everyone has helped me understand the problem more.
danpalmer
+1  A: 

Two points you might consider:

  • Calls of System.gc can be disabled by a commandline parameter (-XX:-DisableExplicitGC), I think the behaviour also depends on the gc algorithm the vm uses. Normally invoking the gc should be left to the jvm
  • As long as there is enough memory available for the jvm I don't see anything wrong in using this memory to increase application and gc performance. As Michael Borgwardt said you can restrict the amount of memory the vm uses at the command line.
Jörn Horstmann
If I restrict the amount of memory available, what will happen if the application would normally want to use more memory? Will it crash or just slow down a lot or what?
danpalmer
It will crash once you pass your XMX. You should NOT call System.gc in your code though, that is not the Java way.
bwawok
If your programm allocates memory and there is no free space left, it will first trigger the gc. So you might see moer gc activity and lower performance. Only if the gc does not free enough memory you will get an OutOfMemoryError. This is more or less like a crash since it is nearly impossible to recover from it.
Jörn Horstmann
A: 

Also you may want to look at what mode the JVM has been started when you deploy it online. My guess its a server VM. Take a look at the differences between the two right here on stackoverflow. Also, see what garbage collector is actually running on the actual deployment. See if you can tweek the GC behaviour, or change the GC algorithm.See the -X options if its a Sun JVM.

naikus
A: 

Basically the JVM takes the amount of memory it is allowed to as needed, in order to make the "new" operation as fast as possible (this is a science in itself).

So if you have a lot of objects being used, and then discarded, you will slowly and surely fill up the available memory. Then you can ask for garbage collection, but it is just a hint, and the JVM may choose not to listen.

So, you need another mechanism to keep memory usage down. The typical approach is to limit the amount of memory with -Xoptions, but be careful since the JVM you use on your pc may be very different from the one you deploy on, and the memory need may therefore be different.

Is there a deliberate requirement for low memory usage? If not, then just let it run and see how the JVM behaves. Use jvisualvm to attach and monitor.

Thorbjørn Ravn Andersen
A: 

Perhaps the server uses more memory because there is a higher load on your app and so more threads are in use? Jetty will use a number of threads to spread out the load if there are a lot of requests. Its worth a look at the thread count on the server versus on your test machine.

Michael Shopsin
There we only have a handful of users at the moment and I watch the usage so we had the same usage for testing in development and live. Also, I gave Jetty the thread pool to use, I know exactly how many threads are in it.
danpalmer