【问题标题】:JVM sending back memory to OS [duplicate]JVM将内存发送回操作系统[重复]
【发布时间】:2010-10-15 02:31:52
【问题描述】:

我有一个关于 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 实际分配的对象)会不会有问题。

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

感谢您的帮助。

【问题讨论】:

  • 哇,标签完全吃掉了你的代码
  • 我已经稍微重新格式化了你的代码 sn-p 以使用 Stackoverflow 的语法高亮功能——我希望你不介意
  • 谢谢,我未能正确显示它。我并不沮丧,我只是新来的 ;-)
  • 一个老问题,但我也希望看到更好的人机工程学或至少外部控制的 JVM 堆提示,以便更好地控制多个 JVM 实例及其各自的资源。

标签: java memory-management jvm


【解决方案1】:

要控制堆返回操作系统,从 Java 5 开始,使用-XX:MaxHeapFreeRatio 选项,如tuning guide 中所述。

如果您觉得您的问题与this one 有明显不同,请指出原因。

【讨论】:

  • 感谢您的回复,我会根据这些提示进行一些测试。
  • 他的部分问题似乎是“如果你有虚拟内存可以依靠,过度分配机器内存是否安全”,这与链接的问题不同。
【解决方案2】:

首先,System.gc() 还不如什么都不做。您真的不能依赖它按照您建议的方式进行垃圾收集。

其次,您需要使用

来监控 GC 的实际情况
-verbosegc -XX:+PrintGCDetails 

在您调用 java.util.或者通过使用 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 以了解世代以及更大/更小堆的权衡是什么。

【讨论】:

  • 这并没有解决问题,这是关于操作系统和 JVM 之间的内存交换,而不是在 JVM 本身内部。
  • @erickson - 你是对的,删除内部 JVM 堆 cmets。在我看来,他指定了一个太大的堆,不需要这样可以分配它更小。不过好像不是这样的。
【解决方案3】:

在您看到明显的减速之前,我不会担心。如果进程分配了未使用的内存,则操作系统将根据需要将未使用的块交换到磁盘。

【讨论】:

  • 因此您的建议是分配至少与我拥有的进程数乘以每个进程的 JVM 堆允许大小一样多的虚拟内存。例如,10 个最大堆为 1GO 的进程,那么我需要加/减 10GB 的虚拟内存吗?
  • 是的,让我们交换一下……完全扼杀表演真是个好主意。
猜你喜欢
  • 2015-07-15
  • 2020-04-04
  • 1970-01-01
  • 2013-06-26
  • 2014-05-26
  • 1970-01-01
  • 2019-11-02
  • 1970-01-01
相关资源
最近更新 更多