Java: How do you really force a GC using JVMTI's ForceGargabeCollection?

旧时模样 提交于 2019-11-27 09:01:48

NetBeans, at least, uses System.gc(): http://hg.netbeans.org/main/annotate/9779f138a9c9/openide.actions/src/org/openide/actions/GarbageCollectAction.java (this is for the little button that shows current heap and lets you start GC). If you follow that link, you'll see that they explicitly run finalizers. If you have a few gig of disk space free, and want to investigate the code yourself, it's available via Mercurial: hg clone http://hg.netbeans.org/main/

As far as I can tell, the "System.gc() is just a hint" dogma originates in pedantic interpretation of the JLS and JVM Spec, which allow for Java implementations that don't have a garbage-collected heap. That, and an incomplete reading of the JavaDoc:

Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

Read the second sentence: "best effort to reclaim space" is a lot stronger than "hint."

That said, there's rarely a reason to call System.gc(). With apologies to Knuth:

We should forget about memory management, say about 97% of the time: explicit garbage collection is the root of all evil

I built a basic java agent allowing to invoke the jvmti ForceGarbageCollection function:

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

This agent is invoked via JNI:

class Garbager {
    public static void main(String[] args) {
        Garbager.garbageMemory();
    }

    static void garbageMemory() {
        forceGarbageCollection();
    }

    private static native void forceGarbageCollection();
}

To compile the agent on 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

To launch the Garbager:

java -agentpath:garbager-agent.so Garbager

Based on this tutorial: Own your heap: Iterate class instances with JVMTI

Yes JNI interface code is needed to use JVMTI API as it is a native API. "native" means that you can only call it directly form native (understan c or c++) code. So if you want to call this API from java you need to write JNI code to interface it.

user1953523

As Anon has said, we have something similar in eclipse to run garbage collector explicitly.

Please have a look at Eclipse: Garbage Collector Button

This seems to work quite well. I suggest you to have a look at the code behind this "Run garbage collector" button and reuse it.

Some members say it uses System.gc() but I cannot confirm it. Eclipse experts can shed some light here.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!