【问题标题】:How can I estimate amount of memory left with calling System.gc()?如何估计调用 System.gc() 时剩余的内存量?
【发布时间】:2010-11-11 23:05:14
【问题描述】:

我有一些使用以下配方的数据处理代码:

  • 尽可能多地读入内存中的数据(称之为“块”)
  • 对块执行处理
  • 将处理后的块写入磁盘
  • 重复
  • ...
  • 合并所有已处理的块以获得最终答案。

当块尽可能少时,最后一个阶段效率最高,因此我希望第一阶段读入尽可能多的数据以适合内存。我可以通过查询Runtime.freeMemory()来做到这一点。

但是,这意味着我需要调用System.gc(),或者Runtime.freeMemory() 返回的数字远小于我可以安全分配的内存量。

我听过一些权威人士说,明确地打电话给System.gc() 是个坏主意。有什么办法可以避免这种情况吗?

【问题讨论】:

    标签: java memory-management garbage-collection


    【解决方案1】:

    即使您在检查您有多少内存之前立即调用 System.gc(),也不能保证确实会发生垃圾回收。我自己真的不会打扰,我会设置一个固定的块大小(最好通过属性或类似配置)并始终使用它。如果程序的其余部分足够简单,则可以只使用块大小加上固定数量的 meg 作为堆大小。如果您的程序的大小由于其他原因而不确定,您可以考虑并排运行两个程序并使用 IPC 机制。

    当然,您的代码很可能需要对内存进行更细粒度的控制,但我会谦虚地建议您使用错误的语言;或者至少是错误的运行时(那里有 RT java 产品,我认为它们更适合这类事情)。

    如果这似乎不是最有用的答案,我很抱歉,但基本上我想知道你是否真的需要这个?

    【讨论】:

      【解决方案2】:

      调用 System.gc() 是一个坏主意的原因很可能是因为它不能保证任何事情。

      调用 System.gc() 是一个坏主意的真正原因是 JVM 最擅长知道运行 GC 的最佳时间;即当堆满时。如果您在其他时间调用 System.gc(),您就是在告诉 JVM 做一些昂贵且浪费的事情。

      回到最初的问题,我认为最好的解决方案是不要尝试编写应用程序来第二次猜测内存分配器。相反,对应用程序进行编码,以便块大小是命令行参数/系统属性/任何内容,并手动调整块大小与 JVM 内存大小。您可能还想确保 JVM 初始内存大小和最大内存大小相同。

      【讨论】:

        【解决方案3】:

        缓存freememory的第一个值,重用它并让VM完成工作。

        【讨论】:

        • 当然,只有当我有一种可靠的方法来衡量我在进行过程中分配了多少内存时,这才会有所帮助。
        • 即使那样它也不起作用,因为 VM 可能已经产生了随后由其他进程分配的页面。但在这种情况下,经验法则是第一个近似值至少是可预测的。
        【解决方案4】:

        非常好的时机。我今天早些时候问了this,得到了一些有用的答案,希望对您有所帮助。

        编辑:这并不能真正回答您的问题,但它指的是调用 System.gc() 不是一个好主意。

        【讨论】:

          【解决方案5】:

          使用 JConsole 或类似的东西

          【讨论】:

          • 使用 JConsole 做什么,抱歉?我必须以编程方式执行此操作。
          【解决方案6】:

          调用 System.gc() 是一个坏主意的原因很可能是因为它不能保证任何事情。

          如果你真的想确定 JVM 会进行垃圾收集,你必须告诉它。一种方式与 JConsole 相同,即通过 JMX。

          http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#local

          【讨论】:

            【解决方案7】:

            使用 JMX 怎么样?特别是MemoryMXbean

            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
            

            还要检查MemoryUsage class

            【讨论】:

              【解决方案8】:

              JVM 工具接口 (jvmti) 有一个名为 ForceGarbageCollection 的方法。您可以编写一些 JNI 来调用它。

              类似

              #include "jvmti.h"
              #include "jni.h"
              
              jvmtiEnv *jvmti;
              
              JNIEXPORT jint JNICALL
              Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
                  (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1);
                  return JNI_OK;
              }
              
              JNIEXPORT void JNICALL my_managled_function_name_that_is_entirely_too_long_to_be_easy_to_use (JNIEnv *env) {
                  error = (*jvmti)->ForceGarbageCollection(jvmti);
              //    you can trap the error if you want;
              }
              

              顺便说一句,这是个坏主意。我只将此代码用于调试(以确保某些类,如侦听器,没有更多可访问的引用。)

              我敢打赌,VM 会在抛出内存错误之前 gc 所有可能的数据。

              【讨论】:

                猜你喜欢
                • 2016-07-02
                • 2011-02-16
                • 1970-01-01
                • 1970-01-01
                • 2021-10-11
                • 2015-01-24
                • 2019-04-26
                • 1970-01-01
                相关资源
                最近更新 更多