This week's book giveaway is in the Servlets forum.
We're giving away four copies of Murach's Java Servlets and JSP and have Joel Murach on-line!
See this thread for details.
The moose likes Java in General and the fly likes Heap used for a simple program seems too much Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Heap used for a simple program seems too much" Watch "Heap used for a simple program seems too much" New topic
Author

Heap used for a simple program seems too much

Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
I have some looping programs that are taking huge amount of memory in our server.
Then I do some investigating by creating a very simple program that simulates the same behavior with the looping programs.
Here's the simple test program I created:



I investigate the program using Java VisualVM and I saw the trend of the heap size used. I run it: first iteration it prints "Test" and then it sleeps. During sleep, I see that the used heap size trend keeps growing and growing. Anybody have any idea why this happens?
Is there something wrong with Thread.sleep() probably?

Thanks in advance for all your help.
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24183
    
  34

This program won't take any memory beyond what the JVM takes at a minimum; you need to adjust your idea of "huge!"


[Jess in Action][AskingGoodQuestions]
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
Thanks for your reply, Ernest.

This program won't take any memory beyond what the JVM takes at a minimum;

I'm not too worry about the exact number but what I'm most concern is actually the growing of the heap size used during sleeping. Why is that?
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4165
    
  21

Not knowing about the tool you are using for measuring, is it running in the same JVM as the test code? Or is it an external application?


Steve
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
It comes with Java 6: http://java.sun.com/javase/6/docs/technotes/guides/visualvm/
It's a separate application.
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4165
    
  21

I ran the code you provided and looked at it with VisualVM and the heap stayed the same size throughout the run (198,880 out of over 5M).
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
How long do you run it? From my example, I think at least you need to run it one hour to see that during Thread.sleep(), the heap size does increasing when you look at the heap charts in the "Monitor" tab.

Which OS are you using? Windows? Linux?
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4165
    
  21

Originally posted by Susan Smith:
How long do you run it? From my example, I think at least you need to run it one hour to see that during Thread.sleep(), the heap size does increasing when you look at the heap charts in the "Monitor" tab.

Which OS are you using? Windows? Linux?


<Added this information after retesting>
I am getting significantly different results when I use a Server JRE (like the one that comes with the JDK 1.6.0.7 download) or when I use a Clien JRE (like one on a stand-alone JRE which I normally use for command line tests like this).

On the server JRE the memory increases rapidly in all test cases listed below, but the GC still cleans it up. There is a significant difference in how the server and client JREs actually work, so probably not a surprise. The conclusion at the end of the email is valid for any case. You have to profile your actual application and find what is holding onto memory and how you can release it.

The rest of this wasted space is about the client side JVM - I am leaving mostly as an example of trouble shooting.

<Original Post>

Windows Vista 64-bit, JRE 1.6.0.7

So when I posted my last response I had it running for roughly 1 hour, I have since let it run continuously and the head used has increased a bit (198K->300K). This is because of the system out and un-collected garbage.

Guessing this could be the problem, I ran a second version of your code with a call to System.gc(), and have been running that for about 13 hours. That one is running constant at about 110K. I have another test that I started this morning that doesn't have any System.out on it. That is running constantly at about 198K.

When doing this type of profiling, it is important to know what you are measuring. In the examples we have running, the sleep isn't causing any memory increase. The uncollected objects produced by the System.out call are. These objects are small, and will be released when a GC eventually happens (which left to its own devices usually happens near when the max heap size is reached - but in my example is asked to run more often).

Examples below are three different loops, sped up to show the effect.






Does this mean using simple System outs will fill your memory and kill your app? No, because the memory is released when a GC is called and when you get near the limit for your application the GC will clean up all that un-used memory.

So the original test was because:
"I have some looping programs that are taking huge amount of memory in our server."
You need to profile the real programs on your server. Determine what 'huge amounts of memory' actually is, where it is being help, if that memory is cleared when garbage is collected, and if that means your server is taking too much load, simply needs its heap size increased, or if you have a memory leak where you aren't releasing resources.
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
Thanks for your help, Steve! I really appreciate it.

For the second code you have below, I still see memory increases.
I can see that memory is released when GC is called by the JVM (when nearing limit of my application) but I still don't understand why it increases.


Also, the original example I gave you is sleeping for 1 hour. I saw the memory increases during that 1 hour period when sleeping.


It's very strange for me why our result is different in this case. Makes me wonder about one thing:
Is JVM behave much different in different Operating System? I use Windows XP.

Note: I got the same result as you for code #1 and code #3 that you did.
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224

Does GC always do this every time?
So it needs to wait until the memory nears the limit of my application then do clean-up?

Thanks
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4165
    
  21

Susan, which JVM are you using? If you do java -version does it tell you you are using a Server or a Client version?

The server version actually does a lot more work in the background as it learns about the code and the system it is running on. It uses more memory to begin with but will optimize the code that gets executed in real world examples (another reason to test on your real code).

The Client JVM will do less optimization of the runtime in exchange for a smaller foot print from the start.

For InfLoop2, when I ran it with a Server JVM the memory climbed during the sleep and then dipped when a GC action occurred. I think this is the same behavior you see. This climb in memory usage is probably related to the 'optimization' the JVM is trying to do. I would have to check out snapshots of memory to be sure...

Does GC always do this every time?
So it needs to wait until the memory nears the limit of my application then do clean-up?


The GC doesn't have to wait until the memory nears the limit of the application, it can run at any time. I think there are different levels of aggressiveness you can give as command line arguments that help nudge the GC to run more or less often, and this is usually implementation dependent (try checking out available options using java -X on the command line).

You can be sure that, when the application reaches near the memory limit the GC will run as soon as there are CPU cycles to run in. So all that needless noise that gets cleaned up each cycle when I did a System.gc() call in InfLoop will not crash an application, it would just get cleaned up later (which I see happening in InfLoop2).
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
(#1)
Thanks for your reply, Steve.
I actually didn't realize there are two different types of JVM.
When do you think we should use SERVER JVM/ and when for CLIENT JVM?

This below is what I've been using for testing the test-code that we do above (including the InfLoop2 program):



(#2)
I will check out the available java -X option.
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3420
    
  12
It appears you still have Java 1.3 on your machine and it is running that rather than java 1.6. Unless you really need 1.3 I would suggest removing it from your machine. If you do still need 1.3 then I suggest you alter your PATH variable so that it finds 1.6 by default.

I don't think this is related to what you are seeing because I believe VisualVM only works with Java 1.5 and 1.6, although I'm not sure what would happen if you ran it with 1.3.

As to the difference between the client and server JVMs. The server JVM is slower to start up but performs better with long running programs. Hence it is better suited to server based programs. The client JVM starts up quicker and so tends to be used for client programs where the perceived start up time may be important.


Joanne
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
It appears you still have Java 1.3 on your machine and it is running that rather than java 1.6. Unless you really need 1.3 I would suggest removing it from your machine. If you do still need 1.3 then I suggest you alter your PATH variable so that it finds 1.6 by default.

I don't think this is related to what you are seeing because I believe VisualVM only works with Java 1.5 and 1.6, although I'm not sure what would happen if you ran it with 1.3.


Joanne, you are absolutely right. I didn't notice that. It's my mistake. It must have found the "java" in class path.
I go inside bin directory of jdk 1.6 and got the correct result below:

Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4165
    
  21

If you run your code in the 1.6 version of the JVM, do you still see the memory increase during the sleep?

When I run on
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)

this does not happen (with your original code that sleeps for an hour). I get a very slow (several hours) increase in memory that occurs just after the output, and only after several iterations (4 before it does it the first time). During the sleep the memory remains constant.
[ August 11, 2008: Message edited by: Steve Luke ]
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
Steve,

I used 1.6 and I saw it increasing around minute 15 (with the original code that sleeps for an hour).
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4165
    
  21

I would classify this as 'kind of weird' that we get different results, but wouldn't worry about it - since be aren't really duplicating real-world situation.

If you want to be sure that the GC will run before the heap gets filled, try running the infinite loop in the smallest possible head size you can.

-- edit --
I also think this may be partly (completely?) due to the connection to Visual VM. If you look at the threads tab, the only ones that are running are the RMI threads used to communicate between VisualVM and the application you are watching.
[ August 11, 2008: Message edited by: Steve Luke ]
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
I looked at the Threads tab during Thread.sleep:

RUNNING:
RMI TCP Connection(1)-...
RMI TCP Accept-0
Attach Listener
Signal Dispatcher

SLEEPING:
JMX server connection timeout 13
RMI Scheduler (0)
Finalizer
Reference Handler

WAIT:
main
Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
Steve, for the test program below that where we got different result.

I got same result with you using JDK 1.4
but different result using JDK 1.5 (memory increases). Not sure why...
Different JVM implementation maybe?

Susan Smith
Ranch Hand

Joined: Oct 13, 2007
Posts: 224
Also not sure when I run the same program above (Windows XP), it reports different memory usage:

Using JDK 1.4 --> Memory usage: 788K, VM size: 8,604 K
Using JDK 1.5 --> Memory usage: 8,688K, VM size: 15,652K
 
jQuery in Action, 2nd edition
 
subject: Heap used for a simple program seems too much
 
Similar Threads
Is paint/paintComponent method called by another thread?
Concurrent Mark Sweep Vs Garbage 1 GC
How to read memory usage for process running in Linux,
Memory usage by Java program in LINUX machine.
Trying to understand better how JVM works.