2010-02-01 35 views
23

我不是在尋找通常的「你只能使用System.gc()」答案提示Java中的GC,這個問題根本就不是這個問題。Java:如何使用JVMTI的ForceGargabeCollection強制GC?

我的問題不是主觀的,而是基於現實:GC 可以被迫在Java中的事實。我們每天使用的很多程序都是這樣做的:IntelliJ IDEA,NetBeans,VisualVM。

他們都可以強制 GC發生。

它是如何完成的?

我把它他們都使用JVMTI和更具體的ForceGarbageCollection(注意「強制」),但我怎麼可以嘗試爲自己?

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

另外請注意,這個問題不是「爲什麼」,我想這樣做:「爲什麼」可能是「好奇」或「類似的VisualVM我們寫一個程序」,等等

這個問題真的是「你如何強制GC使用JVMTI的ForceGarbageCollection」?

是否需要使用任何特殊參數啓動JVM?

是否需要任何JNI?如果是這樣,那麼究竟代碼是什

它只適用於Sun VM嗎?

任何完整和可編輯的例子將是最受歡迎的。

回答

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()。隨着道歉克努特:

我們應該忘記內存管理,說的時候約97%:顯式垃圾收集是一切罪惡的根源

需要
+2

基於迂腐解釋我不會把它教條。大多數JVM都可以簡單地禁用對System.gc()的調用,因此你不能相信它做任何事情。 很多時候,當你有一個寫得很好的應用程序,其中gc工作很有趣時,通過調用System.gc(),引入一個開發人員認爲他可以「確保內存可用」的庫,將它關閉是獲得最佳方式回到你的良好gc表現。 – Fredrik 2012-09-11 05:30:34

+0

用戶仍然有控制權。對於熱點VM,您可以設置「-XX:+ DisableExplicitGC」,或者不要。所以只要你能控制JVM標誌'System.gc()'是相當可靠的。該參數僅適用於無法控制這些標誌的庫編寫器/不能假定它將運行在哪個VM上。這是一般情況(規格)與具體使用情況(所有參數由用戶控制)。 – the8472 2015-09-21 13:25:38

+0

應用程序編寫者通常不能控制JVM標誌。例外情況是應用程序被封裝在啓動器中,以防止用戶或系統管理員調整它們。這不是書信。事實上,該標誌專門用於保護人們免受Java應用程序/應用程序編寫者做愚蠢的事情。 – 2015-09-22 02:34:18

0

是JNI接口代碼使用JVMTI API,因爲它是一個本地API。 「native」意味着你只能直接從本地(understan c或C++)代碼中調用它。所以如果你想從Java調用這個API,你需要編寫JNI代碼來連接它。

0

由於匿名說,我們在日食類似,明確運行垃圾收集器。

請看看Eclipse: Garbage Collector Button

這似乎是工作得很好。我建議你看看這個「運行垃圾收集器」按鈕後面的代碼並重用它。

一些成員說,它使用的System.gc(),但我不能確認。 Eclipse專家可以在這裏介紹一些情況。

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