我对JVM内存管理有疑问(至少对于SUN的内存管理问题)。
我想知道如何控制JVM将未使用的内存发送回操作系统的事实(在我的情况下是Windows)。
我写了一个简单的java程序来说明我的期望。 使用-Dcom.sun.management.jmxremote选项运行它,以便您也可以使用jconsole监视堆。
使用以下程序:
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) {}
}
}
一旦第一个GC完成(预期的内容),内部堆就会自由,但内存只会从第三个GC开始发送回操作系统。在第四个之后,完整分配的内存被发送回操作系统。
如何设置JVM来控制此行为? 实际上我的问题是我需要在服务器上运行几个CITRIX客户端会话,但我希望服务器上运行的JVM尽快释放内存(我的应用程序中只有很少的高消耗内存函数)。
如果无法控制此行为,我是否可以这样做,而是增加操作系统虚拟内存,让操作系统按需使用它而不会出现大的性能问题。 例如,如果在具有足够虚拟内存的4GB服务器上有10个java进程的1GB内存(堆中只有100MB实际分配的对象)会有问题。
我猜其他人已经遇到过这样的问题。
感谢您的帮助。
答案 0 :(得分:15)
要控制堆返回操作系统,从Java 5开始,使用-XX:MaxHeapFreeRatio
选项,如tuning guide中所述。
如果您认为自己的问题与this one存在显着差异,请指出如何处理。
答案 1 :(得分:7)
首先,System.gc()可能也无能为力。你真的不能像你建议的那样依赖它来进行垃圾收集。
其次,您需要使用
监控GC的实际情况-verbosegc -XX:+PrintGCDetails
在你的java调用中。或者通过使用JConsole,它听起来像你正在做的。但那个System.gc()让我害怕你在计算错误的东西......
我怀疑当你说第二次或第三次垃圾收集是它释放内存的时候,你只是错误地计算了垃圾收集。对GC的请求不是GC!因此,请检查PrintGCDetails打印出的日志(interpret them this way)。
实际上我的问题是我需要在服务器上运行几个CITRIX客户端会话,但是我希望服务器上运行的JVM尽快释放内存(我的内存消耗很少)应用程序)。
虽然你的问题是有效的,但你要解决的问题有点阴暗。出于这个原因,JVM需要一个堆大小 - 这样可以保证这个空间可以运行。看起来你倾向于启动一个应用程序,然后等待JVM调整其堆的大小,然后启动另一个这样的您正在超额预订机器上的资源。不要这样做,因为一旦应用程序占用的内存超出了您的预期,它将会爆炸,但它有权获得。
我完全相信你不想以这种方式微观管理Java堆。
阅读足够的http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html以了解代数以及更大/更小堆的权衡。
答案 2 :(得分:0)
在你看到可衡量的减速之前我不会担心。如果进程分配了未使用的内存,则操作系统会根据需要将未使用的块交换到磁盘。