OpenJDK JVM 会将堆内存还给 Linux 吗?
我们有一个长期存在的服务器进程,在短时间内很少需要大量的RAM。我们看到,一旦JVM从操作系统获取了内存,它就永远不会将其返回到操作系统。我们如何要求 JVM 将堆内存返回到操作系统?
通常,此类问题的可接受答案是使用 和 。(例如见1、2、3、4)。但是我们是这样运行java的:-XX:MaxHeapFreeRatio
-XX:MinHeapFreeRatio
java -Xmx4G -XX:MaxHeapFreeRatio=50 -XX:MinHeapFreeRatio=30 MemoryUsage
并且仍然在 VisualVM 中看到这一点:
显然,JVM并不兑现,因为heapFreeRatio非常接近100%,远未接近50%。单击“执行GC”的次数不会将内存返回到操作系统。-XX:MaxHeapFreeRatio=50
内存使用.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);
}
}
}
版本:
> 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
我还尝试过OpenJDK 1.7和Sun Java的1.8。所有行为都类似,没有一个将内存返回给操作系统。
我确实认为我需要这个,交换和分页不会“解决”这个问题,因为将磁盘IO花在分页上接近2GB的垃圾进出只是浪费资源。如果你不同意,请启发我。
我还用 / 写了一点 memoryUsage.c,它确实会将内存返回到操作系统。所以在C中是可能的。也许不是Java?malloc()
free()
编辑:奥古斯托指出,搜索会引导我并且只与.我欣喜若狂,尝试了一下,困惑的是我自己没有找到这个。是的,它确实适用于我的MemoryUsage.java:-XX:MaxHeapFreeRatio
-XX:MinHeapFreeRatio
-XX:+UseSerialGC
但是,当我尝试使用我们真正的应用程序时,并没有那么多:-XX:+UseSerialGC
一段时间后,我发现gc()确实有帮助,所以我做了一个或多或少做的线程:
while (idle() && memoryTooLarge() && ! tooManyAttemptsYet()) {
Thread.sleep(10*1000);
System.gc();
}
这就做到了:
实际上,我以前在我的许多实验中已经看到了这种行为和多次调用,但不喜欢需要GC线程。谁知道随着我们的应用程序和Java的发展,这是否会继续工作。一定有更好的方法。-XX:+UseSerialGC
System.gc()
是什么逻辑迫使我打电话四次(但不是立即),这些东西记录在哪里?System.gc()
为了搜索文档并且只使用,我阅读了java工具/可执行文件的文档,并且在任何地方都没有提到它,并且只适用于.事实上,修复的问题 [JDK-8028391] 使 Min/MaxHeapFreeRatio 标志易于管理说:-XX:MaxHeapFreeRatio
-XX:MinHeapFreeRatio
-XX:+UseSerialGC
-XX:MaxHeapFreeRatio
-XX:MinHeapFreeRatio
-XX:+UseSerialGC
为了使应用程序能够控制如何以及何时允许更多或更少的GC,标志-XX:MinHeapFreeRatio和-XX:MaxHeapFreeRatio应该变得可管理。对这些标志的支持也应在默认并行收集器中实现。
已修复问题的评论说:
对这些标志的支持也已作为自适应大小策略的一部分添加到 ParallelGC 中。
我已经检查过了,在向后移植到openjdk-8的已修复问题中引用的补丁确实包含在我正在使用的openjdk-8版本的源代码包中。因此,它显然应该在“默认并行收集器”中工作,但不像我在这篇文章中演示的那样。我还没有找到任何文档说它应该只与.正如我在这里记录的那样,即使这样也是不可靠/不可靠的。-XX:+UseSerialGC
难道我不能不去经历所有这些箍就能得到并做他们承诺的事情吗?-XX:MaxHeapFreeRatio
-XX:MinHeapFreeRatio