23

私は通常の「System.gc()を使用してJavaでGCをヒントすることしかできません」という答えを探しているわけではありません。これは、この質問の内容ではありません。

私の質問は主観的なものではなく、現実に基づいています。事実として、Java で GC を強制することができます。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 でのみ動作しますか?

完全でコンパイル可能な例は大歓迎です。

4

4 に答える 4

9

少なくとも 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() はヒントに過ぎない」という定説は、ガベージ コレクション ヒープを持たない Java 実装を可能にする JLS および JVM 仕様の衒学的な解釈に端を発しています。それと、JavaDocの不完全な読み取り:

gc メソッドを呼び出すということは、Java 仮想マシンが未使用のオブジェクトをリサイクルして、現在占有しているメモリをすばやく再利用できるようにすることを示唆しています。メソッド呼び出しから制御が戻ると、Java 仮想マシンは、破棄されたすべてのオブジェクトからスペースを再利用するために最善を尽くしています。

2 番目の文を読んでください。「スペースを再利用するための最善の努力」は「ヒント」よりもはるかに強力です。

とはいえ、電話する理由はめったにありませんSystem.gc()。クヌースへの謝罪:

約 97% の場合、メモリ管理を忘れる必要があります。明示的なガベージ コレクションはすべての悪の根源です。

于 2010-03-30T17:39:01.973 に答える
5

jvmtiForceGarbageCollection関数を呼び出すことができる基本的な Java エージェントを作成しました。

#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

このチュートリアルに基づく:ヒープを所有する: JVMTI を使用してクラス インスタンスを反復する

于 2015-09-22T13:40:55.827 に答える
0

アノンが言ったように、ガベージコレクターを明示的に実行するためにEclipseに似たものがあります。

Eclipse: Garbage Collector Buttonをご覧ください。

これはかなりうまくいくようです。この「ガベージ コレクターの実行」ボタンの背後にあるコードを見て、再利用することをお勧めします。

System.gc() を使用しているというメンバーもいますが、確認できません。Eclipse の専門家は、ここでいくつかの光を当てることができます。

于 2015-09-22T01:44:26.323 に答える
0

はい、ネイティブ API であるため、JVMTI API を使用するには JNI インターフェイス コードが必要です。「ネイティブ」とは、ネイティブ (understan c または c++) コードからのみ直接呼び出すことができることを意味します。したがって、この API を Java から呼び出したい場合は、JNI コードを記述してインターフェースに接続する必要があります。

于 2011-11-30T19:41:51.870 に答える