如何通过调用System.gc()来估计剩余的内存量?

时间:2009-07-18 13:12:12

标签: java memory-management garbage-collection

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

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

当有尽可能少的块时,最后一个阶段是最有效的,所以我希望第一阶段读入适合内存的数据。我可以通过查询Runtime.freeMemory()来完成此任务。

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

我听到很多当局说明确调用System.gc()是一个坏主意。有什么办法可以避免这种情况吗?

8 个答案:

答案 0 :(得分:2)

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

当然很可能你的代码需要对内存进行更精细的控制,但我谦虚地建议你使用错误的语言;或者至少是错误的运行时(那里有RT java产品,我认为他们更倾向于这种事情。)

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

答案 1 :(得分:1)

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

调用System.gc()是一个坏主意的真正的原因是JVM最了解运行GC的最佳时间;即当堆满了。如果您在其他时间调用System.gc(),则告诉JVM执行昂贵且浪费的操作。

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

使用JConsole或类似的东西

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

使用JMX怎么样?特别是MemoryMXbean

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();

另请查看MemoryUsage class

答案 7 :(得分:-1)

JVM Tool INterface(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所有可能的数据。