OpenJDK JVM会把堆内存还给Linux吗?

彼得·莫希(PeterV.Mørch):

我们的服务器进程寿命很长,短时间内很少需要大量RAM。我们看到,一旦JVM从操作系统获得内存,就永远不会将其返回给操作系统。我们如何要求JVM将堆内存返回给OS?

通常,对此类问题的公认答案是使用-XX:MaxHeapFreeRatio-XX:MinHeapFreeRatio(参见,例如1234)。但是我们正在像这样运行java:

java -Xmx4G -XX:MaxHeapFreeRatio=50 -XX:MinHeapFreeRatio=30 MemoryUsage

仍然可以在VisualVM中看到:

可视VM内存使用率

Clearly, the JVM is not honoring -XX:MaxHeapFreeRatio=50 as the heapFreeRatio is very close to 100% and nowhere near 50%. No amount of clicking on "Perform GC" returns memory to the OS.

MemoryUsage.java:

import java.util.ArrayList;
import java.util.List;

public class MemoryUsage {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Sleeping before allocating memory");
        Thread.sleep(10*1000);

        System.out.println("Allocating/growing memory");
        List<Long> list = new ArrayList<>();
        // Experimentally determined factor. This gives approximately 1750 MB
        // memory in our installation.
        long realGrowN = 166608000; //
        for (int i = 0 ; i < realGrowN ; i++) {
            list.add(23L);
        }

        System.out.println("Memory allocated/grown - sleeping before Garbage collecting");
        Thread.sleep(10*1000);

        list = null;
        System.gc();

        System.out.println("Garbage collected - sleeping forever");
        while (true) {
            Thread.sleep(1*1000);
        }
    }
}

Versions:

> java -version
openjdk version "1.8.0_66-internal"
OpenJDK Runtime Environment (build 1.8.0_66-internal-b01)
OpenJDK 64-Bit Server VM (build 25.66-b01, mixed mode)

> uname -a
Linux londo 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u5 (2015-10-09) x86_64 GNU/Linux

> lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 8.2 (jessie)
Release:    8.2
Codename:   jessie

I've also tried OpenJDK 1.7 and Sun Java's 1.8. All behave similarly and none give memory back to the OS.

I do think I need this and that swap and paging won't "solve" this, because spending disk IO on paging close to 2GB garbage in and out is just a waste of resources. If you disagree, please enlighten me.

I've also written a little memoryUsage.c with malloc()/free(), and it does return memory to the OS. So it is possible in C. Perhaps not with Java?

Edit: Augusto pointed out that searching would've led me to -XX:MaxHeapFreeRatio and -XX:MinHeapFreeRatio only worked with -XX:+UseSerialGC. I was ecstatic and tried it, puzzled that I hadn't found this myself. Yes, it did work with my MemoryUsage.java:

-XX:+ UseSerialGC使用简单的应用程序

However, when I tried -XX:+UseSerialGC with our real app, not so much:

-XX:+ UseSerialGC无法与实际应用程序一起使用

I discovered that gc() after a while did help, so I made a thread that did more or less:

while (idle() && memoryTooLarge() && ! tooManyAttemptsYet()) {
    Thread.sleep(10*1000);
    System.gc();
}

and that did the trick:

GC线程工作

I had actually previously seen the behavior with -XX:+UseSerialGC and multiple System.gc() calls in some of my many experiments but didn't like the need for a GC thread. And who knows if that'll continue to work as both our app and java evolves. There must be a better way.

What is the logic that forces me to call System.gc() four times (but not immediately), and where is this stuff documented?

In search of documentation for -XX:MaxHeapFreeRatio and -XX:MinHeapFreeRatio only working with -XX:+UseSerialGC, I read the documentation for the java tool/executable and it isn't mentioned anywhere that -XX:MaxHeapFreeRatio and -XX:MinHeapFreeRatio only works with -XX:+UseSerialGC. In fact, the fixed issue [JDK-8028391] Make the Min/MaxHeapFreeRatio flags manageable says:

To enable applications to control how and when to allow for more or less GC, the flags -XX:MinHeapFreeRatio and -XX:MaxHeapFreeRatio should be made manageable. Support for these flags should also be implemented in the default parallel collector.

A comment for the fixed issue says:

Support for these flags have also been added to the ParallelGC as part of the adaptive size policy.

I've checked, and the patch referenced in the fixed issue backported to openjdk-8 is indeed contained in the source package tarball for the openjdk-8 version I'm using. So it should apparently work in "the default parallel collector", but doesn't as I've demonstrated in this post. I haven't yet found any documentation that says it should only work with -XX:+UseSerialGC. And as I've documented here, even this is unreliable/dicey.

Can't I just get -XX:MaxHeapFreeRatio and -XX:MinHeapFreeRatio to do what they promise without having to go through all these hoops?

M.Z :

G1 (-XX:+UseG1GC), Parallel scavenge (-XX:+UseParallelGC) and ParallelOld (-XX:+UseParallelOldGC) do return memory when the heap shrinks. I'm not so sure about Serial and CMS, they didn't shrink their heap in my experiments.

Both parallel collectors do require a number of GCs before shrinking the heap down to an "acceptable" size. This is per design. They are deliberately holding on to the heap assuming that it will be needed in the future. Setting the flag -XX:GCTimeRatio=1 will improve the situation somewhat but it will still take several GCs to shrink a lot.

G1 is remarkably good at shrinking the heap fast, so for the usecase described above I would say it's solvable by using G1 and running System.gc() after having released all caches and class loaders etc.

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6498735

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Openjdk支持JavaFX吗?

在OpenJDK JVM上运行cachegrind

AdoptOpenJDK是否不使用OpenJDK的JVM?

设置OpenJDK JVM故障转储位置

可以在线浏览OpenJDK的源代码吗?

openjdk-r ppa是值得信赖的吗?

仍然支持OpenJDK6吗?

在 Linux 上采用 OpenJDK11 选择

OpenJDK JVM是否与Oracle Java SE JVM相同?

Java 9.0.1 OpenJdk使JVM崩溃并出现AdaptiveWeightedAverage问题

JVM,JDK,JRE和OpenJDK有什么区别?

尽管已安装OpenJDK 8,但是ImageJ找不到JVM

OpenJDK中的JVM参数列表中的“:=”表示什么?

具有大量内存的计算机上的OpenJDK MaxRAMPercentage

OpenJDK和Oracle之间在性能上有区别吗?

可以用科特林OpenJDK的使用吗?

OpenJDK 8是Java SE 8的参考实现吗?

使用OpenJDK运行Minecraft时,我的键盘无响应吗?

在Ubuntu 12.10中内置的OpenJDK,但是不能正常工作吗?

openjdk 是 Java 的完整开源实现以及 jvm 和编译器吗?

在 linux 上为 Openjdk Java 定义/安装的字体在哪里

Centos 64位和openjdk 7上的堆转储错误

不甲骨文的商业热点JVM有过的OpenJDK什么性能优势?

如果我将OpenJDK用作JVM,是否需要打开源代码?

当Java的更新为OpenJDK的11詹金斯在Windows返回不支持JVM错误

为什么不JVM命令`jinfo`在高山openjdk8分布`-flags`?

Tomcat未运行,“评估:/ usr / lib / jvm / java-8-openjdk / bin / java:找不到”

查找安装了/usr/lib/jvm/java-1.8.0-openjdk的软件包

获取错误“/etc/environment: /usr/lib/jvm/java-8-openjdk-amd64: Permission denied”