Utility to access string pool content in JDK 8 HotSpot JVM
Asked Answered
L

1

6

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

Lauree answered 6/2, 2016 at 8:17 Comment(9)
Hmm. I suppose if you did a heap memory dump it would show up in there.Benedicto
Is there any better way than doing heapdump as I don't need all other heap data and also the JVM might be stalled during that timeLauree
Why exactly do you need to do that?Benedicto
I am planning to periodically monitor string being used in JVM and raise alters in backend if they match a specfic patterns as part of some platform level componentLauree
Aha. And why do you want to limit this to the String pool? There are a lot more Strings than make it into the pool. Supposedly that String is some kind of user input. Why not filter on the data intake?Benedicto
Can't restrict on taking user input, as there are various ways to take the input either as library, webservice etc. and I wanted this to work everywhere without user have to do anything specific other than installing a library / script in the system. Also I am ok with monitoring some 80-90 % of data, so string pool should be fine, as most of the strings end up in string poolLauree
I doubt that 80-90% of all strings end up in the string pool. For anything coming from outside (user input, database calls) it is probably closer to 0%. Someone would need to call intern() on the Strings.Benedicto
Hmmm.. got it.. Any other suggestion for my use-case to keep it generic without tying to any specific API? like intercepting string creation (I know it's not possible) or any other idea?Lauree
Although this is certainly NOT a realistic solution for a real-world problem, this reminded me of How to print the whole String pool? ...Oeo
D
10

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.

Dethrone answered 6/2, 2016 at 12:45 Comment(3)
Thanks. I will try to play around with the JVMTI as it wouldn't block the JVM. Is there any way to register a listener whenever a new String is created in JVM and access it?Lauree
As the original question was answered, marking this questions as answered. Raised a separate question for listener to new string creation @ #35263182Lauree
Watch out, IterateThroughHeap does not not block the JVM. Excerp from the documentation: 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. So, this too "pauses the JVM" because it has to be ensured that objects don't change.Frill

© 2022 - 2024 — McMap. All rights reserved.