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

Harish
  • 7,589
  • 10
  • 36
  • 47
  • Hmm. I suppose if you did a heap memory dump it would show up in there. – Thilo Feb 06 '16 at 08:20
  • 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 time – Harish Feb 06 '16 at 08:36
  • Why exactly do you need to do that? – Thilo Feb 06 '16 at 08:37
  • 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 component – Harish Feb 06 '16 at 08:47
  • 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? – Thilo Feb 06 '16 at 08:50
  • 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 pool – Harish Feb 06 '16 at 08:55
  • 1
    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. – Thilo Feb 06 '16 at 09:01
  • 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? – Harish Feb 06 '16 at 09:05
  • Although this is certainly **NOT** a realistic solution for a real-world problem, this reminded me of [How to print the whole String pool?](http://stackoverflow.com/questions/22094111/how-to-print-the-whole-string-pool) ... – Marco13 Feb 06 '16 at 14:05

1 Answers1

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.

apangin
  • 92,924
  • 10
  • 193
  • 247
  • 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? – Harish Feb 07 '16 at 11:31
  • 1
    As the original question was answered, marking this questions as answered. Raised a separate question for listener to new string creation @ http://stackoverflow.com/questions/35262682/notification-of-any-string-object-construction-in-java-8-hotspot-vm – Harish Feb 08 '16 at 05:09
  • 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. – Markus Weninger Feb 22 '16 at 13:33