Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java GC是否将内存释放回操作系统?_Java_Memory Management_Garbage Collection - Fatal编程技术网

Java GC是否将内存释放回操作系统?

Java GC是否将内存释放回操作系统?,java,memory-management,garbage-collection,Java,Memory Management,Garbage Collection,当垃圾收集器运行并释放内存时,该内存会返回操作系统,还是作为进程的一部分保留。我有一种强烈的印象,即内存从来没有真正释放回操作系统,而是作为内存区域/池的一部分保留下来,供同一进程重用 因此,进程的实际内存永远不会减少。这让我想起了这一点,Java的运行时是用C/C++编写的,所以我猜同样的事情也适用于它 更新 我的问题是关于Java的。我之所以提到C/C++是因为我假设Java的分配/解除分配是由JRE使用某种形式的malloc/delete来完成的。本文解释了GC在Java7中是如何工作的。

当垃圾收集器运行并释放内存时,该内存会返回操作系统,还是作为进程的一部分保留。我有一种强烈的印象,即内存从来没有真正释放回操作系统,而是作为内存区域/池的一部分保留下来,供同一进程重用

因此,进程的实际内存永远不会减少。这让我想起了这一点,Java的运行时是用C/C++编写的,所以我猜同样的事情也适用于它

更新

我的问题是关于Java的。我之所以提到C/C++是因为我假设Java的分配/解除分配是由JRE使用某种形式的malloc/delete来完成的。本文解释了GC在Java7中是如何工作的。简而言之,有许多不同的垃圾收集器可用。通常,内存是为Java进程保留的,只有一些GC将其释放到系统中(我认为是根据请求)。但是,Java进程使用的内存不会无限增长,因为Xmx选项定义了一个上限(通常为256m,但我认为它取决于操作系统/机器)。

JVM在某些情况下确实会释放回内存,但是(出于性能原因),每当一些内存被垃圾收集时,这种情况不会发生。它还取决于JVM、操作系统、垃圾收集器等。您可以使用JConsole、VisualVM或其他探查器查看应用程序的内存消耗情况

另请参见此

确实会将内存释放回操作系统,但这样做是不情愿的,因为调整堆的大小是昂贵的,并且假设如果您需要该堆一次,您将再次需要它

一般来说,收缩能力和行为取决于所选的垃圾收集器,JVM版本,因为收缩能力通常在GC本身添加很久之后的后续版本中引入。一些收集器可能还需要传递其他选项以选择收缩。有些人很可能永远不会支持它,例如EpsilonGC。 因此,如果需要堆收缩,则应该针对特定的JVM版本和GC配置进行测试

JDK 8及更早版本 在这些版本中,没有明确的提示内存回收选项,但是您可以通过设置
-XX:GCTimeRatio=19-XX:minheapfreetio=20-XX:maxheapfreetio=30
使GC更具攻击性,这将允许它花费更多的CPU时间来收集和限制一段时间后已分配但未使用的堆内存量GC循环

如果您使用的是并发收集器,您还可以将N设置为某个较低的值,以使GC几乎连续运行并发收集器,这将消耗更多的CPU周期,但会更快地收缩堆。这通常不是一个好主意,但在某些类型的具有大量备用CPU内核但内存不足的机器上,这是有意义的

如果您使用的是G1GC,请注意它只获得了使用jdk8u20的能力,早期版本只能在堆的末尾返回块,这对回收的量有很大的限制

如果您使用的收集器具有默认的暂停时间目标(例如CMS或G1),您还可以放宽该目标以减少对收集器的限制,或者您可以切换到并行收集器以优先考虑占用空间而不是暂停时间

要验证是否发生收缩或诊断GC决定不收缩的原因,您可以使用GC日志记录和
-XX:+PrintAdaptiveSizePolicy
也可以提供洞察,例如,当JVM尝试为年轻一代使用更多内存以达到某些目标时

jdk9 添加了
-XX:-ShrinkHeapInSteps
选项,该选项可用于更积极地应用上一节中提到的选项导致的收缩

对于日志记录
-XX:+PrintAdaptiveSizePolicy
已替换为
-Xlog:gc+ergo

JDK 12 引入了通过
G1PeriodicGCInterval
()为G1GC启用提示内存释放的选项,再次以牺牲一些额外的CPU为代价。JEP在和中也提到了类似的特性

JDK 13
添加了类似的行为,在本例中,默认情况下它是启用的。

如果您偶尔使用G1 collector并调用System.gc()(我每分钟执行一次),Java将可靠地收缩堆并将内存返回给操作系统

自Java12以来,如果应用程序处于空闲状态,G1会自动执行此操作

我建议将这些选项与上述建议结合使用,以实现非常紧凑的常驻流程规模:

-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10
几个月来,我们每天都在一个大型应用程序(整个基于Java的来宾操作系统)上使用这些选项,动态加载和卸载类,Java进程几乎总是保持在400到800 MB之间。

在13 Java中发布,它可以将未使用的堆内存返回给操作系统
请参阅

,即使使用C或C++中的标准堆分配方法不必释放回OS,OS本身也能将映射到进程的新未分配页面保持(因此它似乎不自由)。<代码> java的运行时用C/C++编写,所以我猜同样的事情适用吗?< /C>和java的GC也是用C++编写的…它不是“低于”C++的,到目前为止,没有向操作系统释放堆内存。如果仍然没有达到最大堆大小,那么只会占用额外的内存。这与C中的情况相同,而C还有一个额外的问题,即内存碎片会阻碍内存重用(尽管C可以自己管理Alloc)。JVM从最小堆大小开始,我们可以将最大和最小堆大小设置为相同的值。如果最大和最小堆大小相同,它将预先分配JAVA堆,实际上可能只有少数JAVA对象使用此堆,在这种情况下,GC不会将内存释放回操作系统。GC实际上声称使用的内存是未引用的对象,因此它们可以用于其他对象。它不能直接转化为将内存释放回操作系统。它可以通过以下方式释放内存: