Java线程内存计算

h4cxqtbf  于 2023-01-15  发布在  Java
关注(0)|答案(3)|浏览(139)

是否可以计算每个线程的内存消耗?假设我将我的任务划分为4个线程,那么我想知道每个线程消耗多少内存?我需要它知道我的线程的平均和峰值内存使用。

elcex8rz

elcex8rz1#

正如其他人所指出的,大多数对象都存在于堆中,堆内存是由线程共享的,因此无法确定哪些线程对堆的大小负责。
但是线程确实有自己的内存块:堆栈。

堆栈大小

我记得甲骨文公司的罗恩Pressler在2020年的演讲......

常规螺纹

每个线程都被分配了一定数量的内存给它的stack。由于目前基于OpenJDK的Java实现中的线程是 * 一对一 * Map到主机操作系统的线程的,堆栈大小被任意设置为像meg这样的东西。如果需要,可以分配更多的内存,但不会减少。

虚拟线程

Project Loom中提出的虚拟线程(fibers)使情况更加复杂。
ProjectLoom为Java并发工具添加了新的功能,作为其中的一部分,虚拟线程被 * 多对一 * Map到主机OS线程JVM将管理这些虚拟线程而不是OS,当虚拟线程的代码阻塞时“停放”虚拟线程,以允许另一虚拟线程有时间经由分配给“真实的”平台的执行时间运行。调度“真实的的”平台/内核线程以实际在CPU核心上完成工作由主机OS控制,无论有没有Project Loom(至少在基于OpenJDK的Java实现中)。
作为虚拟线程JVM管理的一部分,每个虚拟线程的堆栈开始时都要小得多,然后根据需要增长和收缩(!)。
由于CPU和内存的高效使用,虚拟线程的成本大大降低,因此我们可以运行更多的虚拟线程,甚至可以在普通硬件上运行数百万个虚拟线程。

jchrr9hc

jchrr9hc2#

总结一下我的评论,线程使用共享内存,因此除了保留的堆栈内存(在jvm启动时设置)之外,没有线程拥有自己的任何数据。
由于您关注的是运行JVM时线程消耗的确切堆大小,因此您可以简单地使用visualvm之类的内存分析器来查看线程创建的类和对象,并假设消耗大小。
你也可以使用ThreadLocal变量来定义属于某个特定线程的对象,这也可以帮助你得到每个线程的确切内存消耗。
你也可以看看ThreadMXBean,但是在最新的jvms中已经没有了。

tkclm6bt

tkclm6bt3#

您可以使用Native Memory Tracking来获取有关线程的一般信息,但我不确定如何单独获取有关每个线程的信息。
启动应用程序时,将-XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics添加到vm选项中:

java -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -jar myjar.jar

现在,如果运行:

$jps -l

在你的机器上找到java进程

$jcmd <PID> VM.native_memory

您将看到如下所示的内容:

Native Memory Tracking:

Total: reserved=2344374KB +4399KB, committed=567362KB +19659KB
...
- Thread (reserved=87894KB, committed=19126KB +756KB)
         (thread #159)
         (stack: reserved=87132KB, committed=18364KB +756KB)
         (malloc=577KB #956)
         (arena=184KB #316)
...

有了这个信息,你可以用19126 KB/159= 120 KB来得到每个线程的平均内存大小,问题是这样做不会单独告诉你每个线程,一些线程会更大,另一些会更小。
您还可以用途:

$jcmd <PID> VM.native_memory baseline
$jcmd <PID> VM.native_memory summary.diff

这将告诉您基线时刻和高峰流量期间可以进行的跑步之间的差异。

  • 提醒一句:启用NMT会带来一些额外的开销。您可能需要权衡启用NMT后在PROD中运行应用程序的风险。*

相关问题