Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

I'm not looking for the usual "you can only hint the GC in Java using System.gc()" answers, this is not at all what this question is about.

My questions is not subjective and is based on a reality: GC can be forced in Java for a fact. A lot of programs that we use daily do it: IntelliJ IDEA, NetBeans, VisualVM.

They all can force GC to happen.

How is it done?

I take it they're all using JVMTI and more specifically the ForceGarbageCollection (notice the "Force") but how can I try it for myself?

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

Also note that this question is not about "why" I'd want to do this: the "why" may be "curiosity" or "we're writing a program similar to VisualVM", etc.

The question is really "how do you force a GC using JVMTI's ForceGarbageCollection"?

Does the JVM needs to be launched with any special parameters?

Is any JNI required? If so, what code exactly?

Does it only work on Sun VMs?

Any complete and compilable example would be most welcome.

like image 856
SyntaxT3rr0r Avatar asked Feb 01 '10 16:02

SyntaxT3rr0r


People also ask

How do you force garbage collection to occur at a certain point?

Garbage collection cannot be forced. Calling System. gc() or Runtime.

Can you force JVM to do garbage collection?

You really can't force Java GC. The Java garbage collection algos are non-deterministic, and while all of these methods can motivate the JVM to do GC, you can't actually force it.

What triggers GC in Java?

Common triggers for garbage collection are Eden space being full, not enough free space to allocate an object, external resources like System. gc(), tools like jmap or not enough free space to create an object.


2 Answers

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

like image 118
Anon Avatar answered Oct 02 '22 14:10

Anon


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

like image 37
gontard Avatar answered Oct 02 '22 12:10

gontard