Java: Как вы действительно заставляете GC использовать JVMTI ForceGargabeCollection?
Я не ищу обычного "вы можете только намекнуть GC на Java, используя ответы System.gc()", это совсем не то, о чем этот вопрос.
Мои вопросы не субъективны и основаны на реальности: GC может быть вынужденным на Java для факта. Многие программы, которые мы используем ежедневно, делают это: IntelliJ IDEA, NetBeans, VisualVM.
У всех может быть force GC.
Как это делается?
Я полагаю, все они используют JVMTI и, более конкретно, ForceGarbageCollection (обратите внимание на "Сила" ), но как я могу попробовать это для себя?
http://java.sun.com/javase/6/docs/platform/jvmti/jvmti.html#ForceGarbageCollection
Также обратите внимание, что этот вопрос не касается "почему", я бы хотел сделать это: "почему" может быть "любопытством" или "мы пишем программу, подобную VisualVM" и т.д.
Вопрос в том, "как вы принудительно используете GC с помощью JVMTI ForceGarbageCollection"?
Нужно ли запускать JVM с любыми специальными параметрами?
Требуется ли какое-либо JNI? Если да, то какой именно код?
Работает ли он только на виртуальных машинах Sun?
Приветствуется любой полный и компилируемый пример.
Ответы
Ответ 1
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 Spec, которые позволяют реализовать Java-реализации, у которых нет кучи мусора. Это и неполное чтение JavaDoc:
Вызов метода gc предполагает, что затраты на виртуальную машину Java к рециркуляции неиспользуемых объектов в чтобы сделать память им в настоящее время занимают повторное использование. Когда управление возвращается из вызов метода, виртуальная машина Java прилагает все усилия для пространство от всех отброшенных объектов.
Прочитайте второе предложение: "Лучшее усилие для освобождения пространства" намного сильнее, чем "намек".
Тем не менее, редко возникает причина называть System.gc()
. Принося извинения Кнуту:
Мы должны забыть о управлении памятью, скажем, около 97% времени: явная сборка мусора - это корень всех злых
Ответ 2
Я создал базовый 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
Основываясь на этом учебнике: Соберите свою кучу: Итерайте экземпляры класса с помощью JVMTI
Ответ 3
Да Код интерфейса JNI необходим для использования JVMTI API, поскольку он является родным API. "native" означает, что вы можете только вызвать его напрямую из собственного (understan c или С++) кода. Поэтому, если вы хотите вызвать этот API из java, вам нужно написать код JNI для его интерфейса.
Ответ 4
Как сказал Anon, у нас есть что-то подобное в eclipse, чтобы явно запустить сборщик мусора.
Пожалуйста, посмотрите Eclipse: кнопка сборщика мусора
Это, кажется, работает очень хорошо. Я предлагаю вам взглянуть на код, стоящий за этой кнопкой "Запустить сборщик мусора", и повторно использовать его.
Некоторые участники говорят, что он использует System.gc(), но я не могу подтвердить это. Эксперты Eclipse могут пролить свет здесь.