Java:如何真正使用JVMTI';什么是强制收集?

Java:如何真正使用JVMTI';什么是强制收集?,java,garbage-collection,jvmti,Java,Garbage Collection,Jvmti,我不是在寻找通常的“您只能使用System.GC()提示Java中的GC”答案,这根本不是这个问题的内容 我的问题不是主观的,而是基于一个现实:GC可以在Java中被强制作为一个事实。我们每天使用的许多程序都可以做到这一点:IntelliJ IDEA、NetBeans、VisualVM 它们都可以迫使GC发生 怎么做的 我认为他们都在使用JVMTI,更具体地说是ForceGarbageCollection(注意“Force”),但我怎么能自己尝试呢 还要注意的是,这个问题不是关于“为什么”我想

我不是在寻找通常的“您只能使用System.GC()提示Java中的GC”答案,这根本不是这个问题的内容

我的问题不是主观的,而是基于一个现实:GC可以在Java中被强制作为一个事实。我们每天使用的许多程序都可以做到这一点:IntelliJ IDEA、NetBeans、VisualVM

它们都可以迫使GC发生

怎么做的

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

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

问题是“如何使用JVMTI的ForceGarbageCollection强制GC”

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

是否需要任何JNI?如果是,具体是什么代码

它只在Sun虚拟机上工作吗


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

至少NetBeans使用System.gc():(这是显示当前堆并允许您启动gc的小按钮)。如果您遵循该链接,您将看到它们显式运行终结器。如果您有几gig的可用磁盘空间,并且希望自己研究代码,那么可以通过Mercurial:
hg clone获得http://hg.netbeans.org/main/

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

调用gc方法表明 Java虚拟机需要付出努力 关于回收未使用的物品 为了让他们的记忆 当前可用于快速访问 重新使用当控件从 方法调用,Java虚拟机 已尽最大努力收回 与所有丢弃对象之间的空间

读第二句:“尽最大努力回收空间”比“暗示”强得多

也就是说,很少有理由调用
System.gc()
。向克努特致歉:

我们应该忘记内存管理,比如说97%的时间:显式垃圾收集是万恶之源


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

正如Anon所说,我们在eclipse中有类似的东西来显式运行垃圾收集器

请看一看

这似乎很有效。我建议您看看这个“运行垃圾收集器”按钮背后的代码,然后重用它


一些成员说它使用System.gc(),但我不能证实。Eclipse专家可以在这里提供一些帮助。

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

#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();
}

要在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
要启动垃圾桶,请执行以下操作:

java -agentpath:garbager-agent.so Garbager


根据本教程:

我不会称之为基于学究式解释的教条。大多数JVM都可以简单地禁用对System.gc()的调用,因此您不能信任它做任何事情。通常情况下,如果你有一个编写良好的应用程序,其中gc工作很有趣,引入了一个库,开发人员认为他可以通过调用System.gc()来“确保内存可用”,关闭它是恢复良好gc性能的最佳方法。用户仍然可以控制它。对于hotspot VM,您可以设置
-XX:+DisableExplicitGC
,也可以不设置。因此,只要您能够控制JVM标志
System.gc()
就相当可靠。此参数仅适用于无法控制这些标志/无法假定它将在哪个VM上运行的库编写器。这是一般情况(规范)与具体用途(所有参数由用户控制)的对比。应用程序编写者通常无法控制JVM标志。例外情况是,应用程序包装在启动器中,以防止用户或系统管理员对其进行调整。这不是迂腐。事实上,该标志专门用于保护人们不受Java应用程序/应用程序编写者做蠢事的影响。
java -agentpath:garbager-agent.so Garbager