Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Utility to access string pool content in JDK 8 HotSpot JVM

Is there any utility or script, either using java or native code, to see list of all strings present in String Pool in JDK 8 HotSpot JVM, without having lot of performance impact on JVM?

Alternatively can I have a listener hooked up whenever a new string is being added into JVM?

Thanks, Harish

like image 515
Harish Avatar asked Feb 06 '16 08:02

Harish


1 Answers

You can easily make such yourself utility using HotSpot Serviceability Agent which is included in JDK by default.

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);
    }
}

Run the tool:
java -cp $JAVA_HOME/lib/sa-jdi.jar:. InternedStrings <PID>

Warning: this an external tool that pauses target JVM process for the time of execution.

A few more Serviceability Agent examples here.

UPDATE

If you wish to scan through all strings, not only those in String Pool, you may use a similar approach; just replace getStringTable().stringsDo() with getObjectHeap().iterateObjectsOfKlass(). Example.

UPDATE 2

It is also possible to iterate through Java Heap from within Java process using JVMTI function IterateThroughHeap. This is going to be less intrusive than Serviceability Agent.

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);
}

The complete example is here.

like image 150
apangin Avatar answered Sep 19 '22 23:09

apangin