实时监控 Java 中的总线程堆栈大小

Posted

技术标签:

【中文标题】实时监控 Java 中的总线程堆栈大小【英文标题】:Live monitoring of total thread stack size in Java 【发布时间】:2021-05-11 13:44:42 【问题描述】:

据我所知,Java 线程堆栈大小取决于 JVM 和操作系统架构,默认情况下(除非设置了 -Xss)在 256k 和 1m 之间变化。有没有一种方法或工具可以查看所有当前运行的线程在运行时消耗的总堆栈大小,比如我可以使用 JDK 包中的 JVisualVM 查看堆大小或元空间大小?我知道这个值可以计算为线程堆栈大小 * 当前正在运行的线程数,但是在运行时监控这个值会很棒。

【问题讨论】:

this 【参考方案1】:

首先,默认堆栈大小是特定于平台的,但这并不意味着特定于平台的默认值会“变化”。我的回忆是,很长一段时间以来,默认值都没有改变(对于任何给定的“架构”)。 (可能从 Java 5 开始,如果不是更早的话。但不要引用我的话!)

您也不能使用默认值来准确确定实际分配了多少堆栈内存,因为:

    可以通过-xss 命令行选项覆盖平台默认值。如您所述。 可以在创建每个Thread 对象时指定非默认堆栈大小。 只有在Thread 启动时才实际分配堆栈。 (当Thread 终止时,它会被释放。)

因此,如果您想测量实际分配的堆栈内存,您需要迭代所有线程并找到它们的实际堆栈大小。第一个应该相对简单:遍历ThreadGroup 树。 (我认为你不能保证你会在遍历中看到所有线程,但这不重要。)第二个更困难,因为私有 Thread.stackSize 字段没有吸气剂......和那个字段只记录应用程序提供给Thread 构造函数的参数。

但是,由于典型应用程序只使用默认堆栈大小,因此计算线程数并乘以默认大小通常可以很好地估计总线程堆栈使用量。

还可以通过使用 Andrei Pangin 的 stackmem 脚本的方法检查进程内存段来推断 JVM 分配的堆栈内存。 (注意这是 Linux 特有的,它依赖于 JVM 向操作系统请求单独的内存段以获取线程堆栈。)

另一方面,如果您想知道当前使用(不仅仅是分配)的堆栈空间量,则很难从应用程序中获得。如果您想通过代理获取它,我怀疑您需要先冻结 JVM。这对于定期监控是不可接受的。

但最重要的是,获取信息将(至少!)不平凡,并且(IMO)可能不值得付出努力。 1 通过查看线程数和乘法来准确测量已分配的堆栈空间,您可以做的事情并不多......

...在运行时监控这个值会很棒。

不相信:-)


1 - 想知道使用了多少堆栈内存有两个可能的原因:您需要优化或好奇。在前一种情况下,知道使用了多少堆栈内存并不能直接告诉您应该使用多少。要确定后者,您实际上需要确定是否有太多线程,或者这些线程的堆栈是否需要与当前一样大。 “原则上”减少堆栈内存使用或因为有人说这是“最佳实践”可能会给您带来麻烦。

【讨论】:

你说的最后两个字!并同意。但是全能的 Pangin wrote a minor snippet for this。当然,这只是为了演示。【参考方案2】:

你可以试试JProfiler。 如果您想在自己尝试之前看到它的实际效果,请查看this

此外,您认为线程堆栈大小在 256k 和 1m 之间变化的想法是绝对正确的。

在 JDK 8 中,HotSpot 安装带有一个名为 Native Memory Tracking 的功能(默认:禁用)。要启用它,请使用:

-XX:NativeMemoryTracking=[off|detail|summary]

启用 NMT 后,您可以使用以下方法检查 Thread 或 Thread Stack 占用的内存占用:

jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]

【讨论】:

以上是关于实时监控 Java 中的总线程堆栈大小的主要内容,如果未能解决你的问题,请参考以下文章

如何使用PHP实时监控Linux服务器的cpu,内存,硬盘信息

通过micrometer实时监控线程池的各项指标

java实时监控局域网共享文件夹并复制文件到指定位置

Spring Boot + WebSocket 实时监控异常

徳哥:PostgreSQL 实时健康监控大屏 - 高频指标

Java JTextField文本框实时监控