Java: Как я могу увидеть, сколько строк хранится в пуле строк? [Дубликат]

Если вы хотите быстро сравнить два блока кода / функций, вы можете сделать:

import timeit

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)
2
задан Harish 6 February 2016 в 09:17
поделиться

1 ответ

Вы можете легко сделать такую ​​же утилиту, используя HotSpot Serviceability Agent , который по умолчанию включен в JDK.

import sun.jvm.hotspot.memory.SystemDictionary;
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.OopField;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;

public class InternedStrings extends Tool {

    @Override
    public void run() {
        // Use Reflection-like API to reference String class and String.value field
        SystemDictionary dict = VM.getVM().getSystemDictionary();
        InstanceKlass stringKlass = (InstanceKlass) dict.find("java/lang/String", null, null);
        OopField valueField = (OopField) stringKlass.findField("value", "[C");

        // Counters
        long[] stats = new long[2];

        // Iterate through the String Pool printing out each String object
        VM.getVM().getStringTable().stringsDo(s -> {
            s.printValueOn(System.out);
            System.out.println();
            stats[0]++;
            stats[1] += s.getObjectSize() + valueField.getValue(s).getObjectSize();
        });

        System.out.printf("%d strings with total size %d\n", stats[0], stats[1]);
    }

    public static void main(String[] args) {
        // Use default SA tool launcher
        new InternedStrings().execute(args);
    }
}

Запустите инструмент: java -cp $JAVA_HOME/lib/sa-jdi.jar:. InternedStrings <PID>

Предупреждение: это внешний инструмент, который приостанавливает целевой процесс JVM на время выполнения.

Еще несколько примеров обслуживания здесь здесь .

UPDATE

Если вы хотите сканировать все строки, а не только в String Pool, вы можете использовать аналогичный подход; просто замените getStringTable().stringsDo() на getObjectHeap().iterateObjectsOfKlass(). Пример .

UPDATE 2

Также можно выполнить итерацию через Java-кучу из Java-процесса с помощью функции JVMTI IterateThroughHeap . Это будет менее навязчивым, чем агент Serviceability.

jint JNICALL stringCallback(jlong class_tag, jlong size, jlong* tag_ptr,
                            const jchar* value, jint value_length, void* user_data) {
    wprintf(L"%.*s\n", value_length, value);
    return 0;
}

JNIEXPORT void JNICALL Java_HeapIterator_printStrings(JNIEnv* env, jclass cls) {
    jvmtiHeapCallbacks callbacks = {NULL, NULL, NULL, NULL, stringCallback};
    (*jvmti)->IterateThroughHeap(jvmti, 0, NULL, &callbacks, NULL);
}

Полный пример: здесь .

7
ответ дан apangin 19 August 2018 в 12:43
поделиться
  • 1
    Благодарю. Я попытаюсь поиграть с JVMTI, так как это не будет блокировать JVM. Есть ли способ зарегистрировать слушателя всякий раз, когда в JVM создается новая String и доступ к ней? – Harish 7 February 2016 в 12:31
  • 2
    В качестве исходного вопроса был дан ответ, отметив эти вопросы в ответ. Поднял отдельный вопрос для слушателя о создании новой строки @ stackoverflow.com/questions/35262682/… – Harish 8 February 2016 в 06:09
  • 3
    Остерегайтесь, IterateThroughHeap делает , а не блокировать JVM. Выдержка из документации: During the execution of this function the state of the heap does not change: no objects are allocated, no objects are garbage collected, and the state of objects (including held values) does not change. As a result, threads executing Java programming language code, threads attempting to resume the execution of Java programming language code, and threads attempting to execute JNI functions are typically stalled. Итак, это тоже «приостанавливает JVM». потому что необходимо обеспечить, чтобы объекты не менялись. – Markus Weninger 22 February 2016 в 14:33
Другие вопросы по тегам:

Похожие вопросы: