views:

929

answers:

5

Hi all,

I have a question regarding the JVM memory management (at least for the SUN's one).

I would like to know how to control the fact that the JVM send the unused memory back to the OS (windows in my case).

I wrote a simple java program to illustrate what I expect. Run it with -Dcom.sun.management.jmxremote option so that you can also monitor the heap with jconsole for example.

With the following program:

package fr.brouillard.jvm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;

public class MemoryFree {
    private BufferedReader reader = new BufferedReader(new
        InputStreamReader(System.in));
    private List<byte[]> usedMemory = new LinkedList<byte[]>();
    private int totalMB = 0;
    private int gcTimes = 0;

    public void allocate(int howManyMB) {
     usedMemory.add(new byte[howManyMB * 1024 * 1024]);
     totalMB += howManyMB;
     System.out.println(howManyMB + "MB allocated, total allocated: " +
                totalMB + "MB");
    }

    public void free() {
     usedMemory.clear();
    }

    public void gc() {
     System.gc();
     System.out.println("GC " + (++gcTimes) + " times" );
    }

    public void waitAnswer(String msg) {
     System.out.println("Press [enter]" + ((msg==null)?"":msg));
     try {
      reader.readLine();
     } catch (IOException e) {
     }
    }

    public static void main(String[] args) {
     MemoryFree mf = new MemoryFree();
     mf.waitAnswer(" to allocate memory");
     mf.allocate(20);
     mf.allocate(10);
     mf.allocate(15);
     mf.waitAnswer(" to free memory");
     mf.free();
     mf.waitAnswer(" to GC");
     mf.gc();
     mf.waitAnswer(" to GC");
     mf.gc();
     mf.waitAnswer(" to GC");
     mf.gc();
     mf.waitAnswer(" to GC");
     mf.gc();
     mf.waitAnswer(" to exit the program");

     try {
      mf.reader.close();
     } catch (IOException e) {}
    }
}

The internal heap is free once the first GC is done (what is expected) but the memory is only sent back to the OS starting from the third GC. After the fourth, the full allocated memory is sent back to the OS.

How to setup the JVM to control this behaviour? In fact my problem is that I need to run several CITRIX clients sessions on a server, but I would like the running JVMs on the server to free the memory as soon as possible (I have only few high consuming memory functions in my application).

If this behaviour cannot be controlled, can I let it like this and increase instead the OS virtual memory and let the OS using it as it wants without big performance issues. For example, would there be issues to have 10 java process of 1GB memory (with only 100MB real allocated objects in the heap) on a 4GB server with enough virtual memory of course.

I guess that other people already faced such questions/problems.

Thanks for your help.

+4  A: 

First of all, System.gc() might as well do nothing. You really can't rely on it to do a garbage collection the way you are suggesting.

Second, you'll want to monitor what is actually going on the with GC by using

-verbosegc -XX:+PrintGCDetails

in your invocation of java. Or by using JConsole, which it sounds like you're doing. But that System.gc() has me scared that you're counting the wrong thing...

I suspect that when you say that the second or third garbage collection is when it frees the memory, you're just miscounting the garbage collections. A request to GC is not a GC! So check the logs (interpret them this way) that PrintGCDetails prints out.

In fact my problem is that I need to run several CITRIX clients sessions on a server, but I would like the running JVMs on the server to free the memory as soon as possible (I have only few high consuming memory functions in my application).

While your problem is valid, the solution you're going for is a little shady. The JVM needs a heap size for exactly this reason - so that it can be guaranteed this space to run in. It seems like you're leaning towards launching an app, then waiting for the JVM to size its heap down, then launching another such that you're overbooking the resources on the machine. Don't do that, because it will all blow up once an app is taking more memory than you figured it would, but which it is entitled to.

I fully believe that you don't want to be micro managing Java's heap this way.

Read enough of http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html to understand the generations and what the trade offs of a larger/smaller heap are.

Kai
This doesn't address the question, which is about the exchange of memory between the OS and JVM, not within the JVM itself.
erickson
@erickson - You're right, remove internal JVM heap comments. It seemed to me he was specifying a too-large heap and didn't need to be so could allocate it smaller. Doesn't seem to be the case though.
Kai
A: 

I wouldn't worry about it until you see measurable slowdowns. If a process has memory allocated that it isn't using, the OS will swap the unused chunks to disk as needed.

Andrew Medico
So your suggestion would be to allocate at least as much virtual memory as the number of process I have multiply by the allowed size of the JVM heap of each process. For example, 10 process with a max heap of 1GO, then I need plus/minus 10GB of virtual memory?
Matthieu BROUILLARD
A: 

Thanks Kai for your answers.

But I think i did not explain me correctly. I do not want to force GC to occur (was just for the example to illustrate what is occuring), but I would like to be able to optimize the number of java process running on a single server. If I need to allow each java process to consume 1GB memory (for some big rare consuming functions in the application) I would like to be sure of either:

  • the JVM send back the memory to the OS once the memory has been free in the heap, so that other concurrent process can be launched
  • or the OS will correctly push back unused heap space to the virtual memory

Does it make more sense expressed like this?

Matthieu BROUILLARD
I understand better now; I edited my answer.
Kai
+2  A: 

To control return of heap to the OS, from Java 5 onward, use the -XX:MaxHeapFreeRatio option, as described in the tuning guide.

If you feel your question is meaningfully different from this one, please point out how.

erickson
Thanks for your reply, I will do some tests with those hints.
Matthieu BROUILLARD
It does seem that part of his question is "is it safe to overallocate the machine memory if you have virtual memory to fall back on", which is different from the linked question.
Kai
A: 

Set the minimum and maximum size of the heap to the same value, using -Xms and -Xmx

for example java -Xms 64m -Xmx 64m ...

Tony BenBrahim