【问题标题】:Utility to access string pool content in JDK 8 HotSpot JVM在 JDK 8 HotSpot JVM 中访问字符串池内容的实用程序
【发布时间】:2016-02-06 08:17:28
【问题描述】:

是否有任何实用程序或脚本(使用 java 或本机代码)来查看 JDK 8 HotSpot JVM 中字符串池中存在的所有字符串的列表,而不会对 JVM 产生很大的性能影响?

或者,我可以在将新字符串添加到 JVM 时连接一个侦听器吗?

谢谢, 哈里什

【问题讨论】:

  • 嗯。我想如果你做了一个堆内存转储它会出现在那里。
  • 有没有比做 heapdump 更好的方法,因为我不需要所有其他堆数据,而且 JVM 在那段时间可能会停止
  • 您究竟为什么需要这样做?
  • 我计划定期监控 JVM 中使用的字符串,如果它们匹配特定模式作为某些平台级组件的一部分,则在后端引发更改
  • 我怀疑所有字符串的 80-90% 最终都在字符串池中。对于来自外部的任何东西(用户输入、数据库调用),它可能接近于 0%。有人需要在字符串上调用intern()

标签: java string jvm jvm-hotspot


【解决方案1】:

您可以使用 JDK 默认包含的 HotSpot Serviceability Agent 轻松制作这样的实用程序。

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 进程的外部工具。

更多Serviceability Agent示例here

更新

如果您希望扫描所有字符串,而不仅仅是字符串池中的字符串,您可以使用类似的方法;只需将getStringTable().stringsDo() 替换为getObjectHeap().iterateObjectsOfKlass()Example.

更新 2

还可以使用 JVMTI 函数 IterateThroughHeap 在 Java 进程中迭代 Java 堆。这将比 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);
}

完整的例子是here

【讨论】:

  • 谢谢。我将尝试使用 JVMTI,因为它不会阻塞 JVM。有没有办法在JVM中创建一个新的String并访问它时注册一个监听器?
  • 原始问题已回答,将此问题标记为已回答。为新字符串创建@stackoverflow.com/questions/35262682/… 的听众提出了一个单独的问题
  • 当心,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”,因为必须确保对象不会改变。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多