强制JVM释放内存

6

我改进了代码以从垃圾回收器中获得更好的结果。

现在当我调用System.gc()时,它确实释放了所有内存。但是当我没有调用System.gc()时观察内存使用情况,应用程序确实会保留和使用越来越多的内存。

这是否意味着我的改进起作用了,我已经正确地处理了所有引用并且可以忽略JVM自行释放内存的方式?或者我的代码中存在其他问题,导致JVM在不执行垃圾回收的情况下保留更多的内存。

4个回答

5
取决于您的JVM使用哪个GC。如果是JDK9,则可能是'贪婪'的G1,当涉及内存消耗时,它会根据内存需求进行动态分配/释放,因此根据检查内存利用方式,它可能会占用大量内存(而实际上只是保留内存并动态使用/释放)。
您可以使用jstat检查内存消耗情况。
至于GC和内存消耗分析,请参考以下内容:High memory usage issues with G1 Garbage collector+Minimize Java Memory Usage – Choose the Right Garbage Collector

谢谢,我会看一下。 - Dennis

3

未使用的内存是浪费的内存。

为什么要显式调用System.gc()。在我看来,你应该永远不要调用它,而是让JVM决定何时运行GC。(如果你是一个初学者,JVM可以比你做出更好的决策。只有当你真正知道自己在做什么时才调用System.gc()。)通常调用System.gc()是一种不良实践

System.gc()只是向JVM发出运行GC的请求/提示。这并不意味着GC一定会运行。

在Java中可能存在内存泄漏,但在你的情况下这肯定不是需要关注的问题,因为正如你所提到的,当你调用System.gc()时,你会看到一些内存得到释放。(所以你没有仍然持有未使用对象的引用,这可能会阻止GC清理这些对象。)

你为什么认为这是你代码的问题?可能是因为不再需要更多的内存,或者如果需要内存,你已经有了足够的内存(换言之,GC不会释放内存,因为程序还有很多东西要运行,那么GC为什么要清理内存呢?)。


谢谢你的回答。然而,我不想使用System.gc()。我只是用它作为一个工具来查看内存是否会被释放。我的代码出了问题,但现在我已经解决了。但我想知道为什么JVM不会自动释放内存,或者为什么它需要这么长时间才能释放它。 - Dennis
垃圾回收花费计算时间来获得可用空间。很明显,“普通程序”想要这种特定的权衡并不一定符合利益。 - user10762593
1
@Dennis,JVM很少“释放”内存。大多数情况下,垃圾回收将识别未使用的内存,唯一的影响是您的监控程序将显示它为未使用。现代操作系统也不依赖于释放内存。内存被虚拟化,如果另一个程序需要物理内存,它可以获取已释放或未释放的内存。因此,这个答案说得很好,“未使用的内存是浪费的内存”,无论是JVM还是操作系统都不会花费资源来仅仅向您呈现更多的“空闲内存”数字。那只是一个数字,而不是有意义的东西。 - Holger

1
无法强制JVM释放内存,System.gc()仅是提示。由GC来管理内存(请注意,有各种类型的内存,例如堆、元空间、非堆)。每个GC算法都有多个可调参数,但都不会提供按需释放内存的选项。
JVM在启动时保留内存,并从操作系统请求额外的内存,直到达到配置的限制。它以块增量方式进行请求,一次请求MB或更多内存,因为逐字节从操作系统请求内存将非常低效。

我知道这只是一个提示,但我的问题是,当System.gc()释放内存时,这是否意味着我所有的引用都正确?因为JVM本身并不真正地释放内存。 - Dennis
如果您想了解内存何时返回给操作系统,请参见 https://dev59.com/ZUXRa4cB1Zd3GeqPveEw#324505。 - Karol Dowbecki

1
当然,你的程序可能存在内存泄漏的可能性,这意味着你的程序一直在分配内存而没有释放它(例如,在不断增长的列表或映射中)。您需要使用内存分析器来确保您没有遭受这种情况。
除此之外,如果虚拟机似乎一直在分配内存而没有释放它,我认为不用担心。这是现代虚拟机的工作方式,特别是在“客户端”模式下:只要有足够的空闲内存,它们就不会浪费时间进行垃圾回收。当接近内存限制时,垃圾回收器才会启动。(“客户端”与“服务器”模式是JVM参数,如果您想要尝试,可以在此处了解更多信息:“java-server”和“java-client”之间的真正区别是什么?
除此之外,你可以做到以下几点:
a)确保执行完整GC的机制实际上正在执行完整GC。我所知道的最好的机制(不能保证有效,但据我所知似乎有效)是分配一个仅通过软引用引用的对象,然后不断调用GC,直到软引用变为空为止。
在调试运行中(例如启用了断言),每隔几秒钟在单独的线程上触发一次完整的GC。然后,如果查看VM消耗的内存,它应该大致保持不变。如果没有,则表示存在内存泄漏。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接