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

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

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

他们都可以强制 GC发生。

怎么做?

我认为他们都使用JVMTI,更具体地说是ForceGarbageCollection (注意“Force”),但我怎么能为自己尝试呢?

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

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

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

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

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

它只适用于Sun VM吗?

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

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%的时间说:显式垃圾收集是万恶之源

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

 #include  #include  #include  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 

基于本教程: 拥有您的堆:使用JVMTI迭代类实例

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

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

请看一下Eclipse:垃圾收集器按钮

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

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