【问题标题】:Release java memory for OS at runtime.在运行时为操作系统释放 java 内存。
【发布时间】:2012-08-08 19:15:48
【问题描述】:

假设我有一个 Swings Java 应用程序, 我将最小堆设置为 64MB,最大堆设置为 2GB, 当用户启动应用程序时,登录屏幕 会显示,此时app使用64MB,对吗? 在我的 Windows 7 中,我可以看到 java 应用程序分配了 64MB 来自操作系统的内存资源监视器(实际上,它超过 64MB,因为 JVM 需要一些内存来执行它的任务)。

之后用户做了一些非常繁重的工作,然后应用程序使用 2G。 然后用户退出应用程序,再次显示登录屏幕(应用程序尚未关闭)。这时应用程序的真实内存 正在使用 64MB(假设这是完美的内存管理应用程序), 但是对于这个应用程序仍然使用 2G 内存的操作系统,我可以在操作系统的资源监视器上看到它。

我希望我的应用程序在不需要使用大内存时将内存释放给操作系统。我可以在运行时使用 java 应用程序吗?

我的意思是当我的应用程序需要使用 64MB 内存时, 然后操作系统只给它64MB, 当它需要 2GB 内存时,操作系统会给它 2GB, 之后它需要 64MB 的内存,然后操作系统再次给它 64MB, 我不希望它浪费 2000MB - 64MB = 1936MB。

我可以这样做吗?

谢谢,

【问题讨论】:

标签: java jvm


【解决方案1】:

我已经发布了我的测试结果over there。基本上,MaxHeapFreeRatio 并不是每个 GC 实现都遵守的,更糟糕​​的是,似乎有必要有足够的堆活动才能及时触发它,即。可能是您需要 2 次完整的 GC 运行才能将内存实际释放到操作系统。如果您有 X GB 的突发内存占用,那么您可能必须分配该数量的 1 或 2 倍才能触发堆缩小。或者您手动调用 System.gc()。

如果性能不是问题,而内存占用才是最重要的,请尝试:

-XX:UseSerialGC -Xms16M -Xminf=5 -Xmaxf=10

【讨论】:

  • 有趣的博客。干得好。不过我想知道你等了多久。示例:在您完成循环和箍然后闲置 1 小时后,JVM 内存消耗将如何(从操作系统上看)? “空闲”是指没有内存分配活动。
  • AFAIK GC 是由内存更改触发的......所以只是等待根本不会做任何事情。自己试一下,代码就在那里。
  • 有趣的帖子。顺便说一句,对于 Oracle 和 IBM VM,Xminf 和 Xmaxf 的值似乎应该是百分比(从 0.0 到 1.0)并且没有前导 =。请参阅here、here 和 here。
  • 在我看来,在您的示例中,使 VM 将内存释放回操作系统的只是 -XX:UseSerialGC,因为由于语法错误,Xminf 和 Xmaxf 被忽略(请参阅我之前的评论)。使用正确的语法,您确实可以使用 Xminf 和 Xmaxf 调整此版本。
  • 我只使用 Sun/Orcale JVM。它在那里工作。如果您使用任何特殊的东西,当然由您自己检查。
【解决方案2】:

我希望我的应用程序在不需要使用大内存时将内存释放给操作系统。我可以在运行时使用 java 应用程序吗?

不,你不能。

在某些情况下,GC 会自行将内存释放回操作系统,但我不知道有任何 JVM 允许应用程序告诉 GC 这样做。最重要的是,GC 对此相当保守,因为......作为一般规则...... JVM 将使用更多内存更有效地运行,并且不断向操作系统请求/返回内存是低效的。


请注意,GC 调整选项-XX:MaxHeapFreeRatio 可用于指定在 GC 归还内存之前可用堆与已用堆的最大比率。然而,也有并发症。例如,并非所有可用的 GC 都尊重此选项。如果你打算尝试这种方法,我建议你做一些研究......不要期待奇迹。

【讨论】:

  • 是GC的问题吗?我不这么认为。 GC 清除对象并释放堆,但处理堆是另一回事。
  • @AmirPashazadeh - 你需要阅读 JVM 源代码才能知道返回内存的代码实际在哪里。
  • 请注意,只有在使用singThreadGC时才会考虑这个设置。在使用此选项时未观察到任何行为变化后,我在此答案 stackoverflow.com/a/8170123/775513 中发现了这一点。
  • @cproinger - 我认为你应该小心从那个问答中概括。问题是关于 Java 5 JVM 的行为。从那时起,Java 内存管理/垃圾收集发生了很大变化。
【解决方案3】:

hotspot 中的serialgc 会返还内存……至少以前是这样。你的表现会一飞冲天。

IBM J9 jvm 中的所有垃圾收集器都会释放内存。我不确定这个 jvm 是否可以免费下载...

最好的答案是,你为什么担心?如今,内存非常便宜,而免费内存就是浪费内存。这真的有问题吗?无论如何,操作系统都会将多余的未使用内存分页到磁盘。最好的答案是忽略它。 :)

您也可以考虑使用谷歌搜索堆外存储,也许是 Teracotta/eh 缓存。

编辑:

我刚刚在 JDK1.7u6 中注意到,使用具有小 Xms 和大 Xmx 的 G1GC,垃圾收集器会在释放多余对象的几次垃圾收集后减小堆的大小。

【讨论】:

  • 因为我的客户不喜欢它。在 99% 的情况下,他们完成了消耗大约 300 - 400MB RAM 的工作。有 1% 的情况是他们做了一些繁重的工作,然后应用程序使用了 2GB 的 RAM。他们说我的应用程序在没有必要这样做时使用了太多内存。他们需要内存用于其他应用程序。似乎每当 java 应用程序以最大内存使用运行时,当它以最小内存使用运行时,它不会将内存还给操作系统。对吗?
  • 查看更新,我发现了一些新信息... :) 很抱歉您的客户如此挑剔,他们不应该如此。他们应该依靠他们的操作系统来正确管理内存。
  • 好吧,要求 java 也正确处理内存并不是不合理的(我作为 java 开发人员这么说)。一般来说,我不同意无限期甚至长时间保持当前所需内存的 5-10 倍是正确的行为,除非机器上没有其他东西在运行。
  • 它是正确的行为。不正确的行为是人们对记忆如何运作的理解。您会惊讶地发现 JDK、垃圾收集器和系统上的页表实际发生了什么。这都是一个巨大的幻想:)
  • “内存很便宜”是一句很棒的台词,只要你有额外的插槽。当您运行 256GB/slice 并希望在 VM/容器中同时运行 3-4 个 java 程序时与我交谈。如果其中任何一个占用大量内存,它可能会削弱其他人。要么是这样,要么你人为地将它们限制在每个的一小部分,从而浪费资源以防万一其他地方需要它们。这是双输。
【解决方案4】:

您可以处理对象并建议垃圾收集器完成其工作,但如果 GC 认为没有必要,则该请求将被忽略。总而言之,“不”。

注意分配给 Java 应用程序的内存。在应用程序之前设置。启动,并且不可调整。

【讨论】:

    【解决方案5】:

    尝试将部分代码分叉到单独的线程中,并在不再需要时将其丢弃。

    【讨论】:

    • 这在 Java 的上下文中毫无意义。 (如果您指的是 Java 线程,那么这将无法实现 OP 试图做的事情——说服 JVM 将堆内存还给操作系统。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 2010-11-17
    • 2019-11-02
    • 2015-05-03
    相关资源
    最近更新 更多