Java:你如何使用JVMTI的ForceGargabeCollection强制GC?

时间:2010-02-01 16:34:01

标签: java garbage-collection jvmti

我不是在寻找通常的“你只能使用 System.gc()”回答用Java提示GC,这根本不是这个问题的关键所在。

我的问题不是主观的,而是基于现实:GC 可以强制使用Java来实现。我们每天使用的很多程序都是这样做的:IntelliJ IDEA,NetBeans,VisualVM。

他们都可以强制 GC发生。

怎么做?

我认为它们都是使用JVMTI,更具体地说是 ForceGarbageCollection (注意“强制”),但我该如何为自己尝试呢?

http://java.sun.com/javase/6/docs/platform/jvmti/jvmti.html#ForceGarbageCollection

另请注意,这个问题不是“为什么”我想要这样做:“为什么”可能是“好奇心”或“我们正在编写类似于VisualVM的程序”等等。

问题实际上是“你如何使用JVMTI的ForceGarbageCollection强制GC”?

是否需要使用任何特殊参数启动JVM?

是否需要任何JNI?如果是这样,究竟是什么代码?

它只适用于Sun VM吗?

任何完整且可编辑的例子都是最受欢迎的。

4 个答案:

答案 0 :(得分:10)

NetBeans,至少使用System.gc():http://hg.netbeans.org/main/annotate/9779f138a9c9/openide.actions/src/org/openide/actions/GarbageCollectAction.java(这是用于显示当前堆的小按钮,并允许您启动GC)。如果您遵循该链接,您将看到他们明确地运行终结器。如果您有一些免费的磁盘空间,并且想要自己调查代码,可以通过Mercurial获取:hg clone http://hg.netbeans.org/main/

据我所知,“System.gc()只是一个提示”教条起源于对JLS和JVM规范的迂腐解释,它允许Java实现没有垃圾收集堆。那,以及JavaDoc的不完整阅读:

  

调用gc方法表明了这一点   Java虚拟机花费精力   回收未使用的物品   为了使他们记忆   目前可以快速占用   重用。当控制从中返回时   方法调用,Java虚拟机   我已尽最大努力收回   所有丢弃物体的空间。

阅读第二句话:“尽力回收空间”比“提示”要强很多。

那就是说,很少有理由打电话给System.gc()。向Knuth道歉:

  

我们应该忘记内存管理,大约97%的时间说:显式垃圾收集是所有邪恶的根源

答案 1 :(得分:4)

我构建了一个基本的java代理,允许调用jvmti ForceGarbageCollection函数:

#include <stdlib.h>
#include <stdio.h>
#include <jvmti.h>


typedef struct {
 jvmtiEnv *jvmti;
} GlobalAgentData;

static GlobalAgentData *gdata;

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
{
  printf("load garbager agent\n");
  jvmtiEnv *jvmti = NULL;

  // put a jvmtiEnv instance at jvmti.
  jint result = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
  if (result != JNI_OK) {
    printf("ERROR: Unable to access JVMTI!\n");
  }

  // store jvmti in a global data
  gdata = (GlobalAgentData*) malloc(sizeof(GlobalAgentData));
  gdata->jvmti = jvmti;
  return JNI_OK;
}


extern "C"
JNIEXPORT void JNICALL Java_Garbager_forceGarbageCollection(JNIEnv *env, jclass thisClass) 
{
  printf("force garbage collection\n");
  gdata->jvmti->ForceGarbageCollection();
}

通过JNI

调用此代理
class Garbager {
    public static void main(String[] args) {
        Garbager.garbageMemory();
    }

    static void garbageMemory() {
        forceGarbageCollection();
    }

    private static native void forceGarbageCollection();
}

在MacOSX上编译代理:

clang -shared -undefined dynamic_lookup -o garbager-agent.so -I /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/include/ -I /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/include/darwin garbager-agent.cpp

启动Garbager

java -agentpath:garbager-agent.so Garbager

基于本教程:Own your heap: Iterate class instances with JVMTI

答案 2 :(得分:0)

是使用JVMTI API需要JNI接口代码,因为它是本机API。 “native”意味着您只能直接从本机(understan c或c ++)代码中调用它。因此,如果你想从java调用这个API,你需要编写JNI代码来连接它。

答案 3 :(得分:0)

正如Anon所说,我们在eclipse中有类似的东西可以明确地运行垃圾收集器。

请查看Eclipse: Garbage Collector Button

这看起来效果很好。我建议你看看这个“运行垃圾收集器”按钮背后的代码并重用它。

有些成员说它使用System.gc()但我无法确认。 Eclipse专家可以在这里阐明一些。