JVM 将内存发送回操作系统

2022-09-02 13:21:38

我有一个关于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个1GB内存的java进程(堆中只有100MB的实际分配对象)是否会有问题。

我猜其他人已经面临这样的问题/问题。

感谢您的帮助。


答案 1

要控制从 Java 5 开始向操作系统返回堆,请使用该选项,如调优指南中所述。-XX:MaxHeapFreeRatio

如果您觉得您的问题与此问题有有意义的不同,请指出如何。


答案 2

首先,System.gc() 可能什么都不做。你真的不能依靠它来按照你建议的方式进行垃圾回收。

其次,您需要使用以下命令监视GC的实际情况

-verbosegc -XX:+PrintGCDetails 

在你调用 java 时。或者通过使用JConsole,这听起来像是你正在做的事情。但是那个System.gc()让我害怕你算错了东西......

我怀疑,当你说第二个或第三个垃圾回收是当它释放内存时,你只是错误地计算了垃圾回收。对 GC 的请求不是 GC!因此,请检查PrintGCDetails打印出来的日志(以这种方式解释它们)。

事实上,我的问题是我需要在服务器上运行多个CITRIX客户端会话,但我希望服务器上正在运行的JVM尽快释放内存(我的应用程序中只有很少的高消耗内存功能)。

虽然您的问题有效,但您要寻求的解决方案有点阴暗。正是出于这个原因,JVM 需要堆大小 - 这样就可以保证它运行此空间。看起来你倾向于启动一个应用程序,然后等待JVM缩小其堆的大小,然后启动另一个应用程序,这样你就超额预订了计算机上的资源。不要这样做,因为一旦应用程序占用的内存比您想象的要多,它就会全部爆炸,但它有权这样做。

我完全相信你不想以这种方式微观管理Java的堆。

阅读足够多的 http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html,以了解几代人以及更大/更小的堆的权衡是什么。