Search code examples
javastringjvmjvm-hotspot

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


Solution

  • 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.