是否可以计算每个线程的内存消耗?假设我将我的任务划分为4个线程,那么我想知道每个线程消耗多少内存?我需要它知道我的线程的平均和峰值内存使用。
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和内存的高效使用,虚拟线程的成本大大降低,因此我们可以运行更多的虚拟线程,甚至可以在普通硬件上运行数百万个虚拟线程。
jchrr9hc2#
总结一下我的评论,线程使用共享内存,因此除了保留的堆栈内存(在jvm启动时设置)之外,没有线程拥有自己的任何数据。由于您关注的是运行JVM时线程消耗的确切堆大小,因此您可以简单地使用visualvm之类的内存分析器来查看线程创建的类和对象,并假设消耗大小。你也可以使用ThreadLocal变量来定义属于某个特定线程的对象,这也可以帮助你得到每个线程的确切内存消耗。你也可以看看ThreadMXBean,但是在最新的jvms中已经没有了。
tkclm6bt3#
您可以使用Native Memory Tracking来获取有关线程的一般信息,但我不确定如何单独获取有关每个线程的信息。启动应用程序时,将-XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics添加到vm选项中:
-XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics
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
这将告诉您基线时刻和高峰流量期间可以进行的跑步之间的差异。
3条答案
按热度按时间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和内存的高效使用,虚拟线程的成本大大降低,因此我们可以运行更多的虚拟线程,甚至可以在普通硬件上运行数百万个虚拟线程。
jchrr9hc2#
总结一下我的评论,线程使用共享内存,因此除了保留的堆栈内存(在jvm启动时设置)之外,没有线程拥有自己的任何数据。
由于您关注的是运行JVM时线程消耗的确切堆大小,因此您可以简单地使用visualvm之类的内存分析器来查看线程创建的类和对象,并假设消耗大小。
你也可以使用ThreadLocal变量来定义属于某个特定线程的对象,这也可以帮助你得到每个线程的确切内存消耗。
你也可以看看ThreadMXBean,但是在最新的jvms中已经没有了。
tkclm6bt3#
您可以使用Native Memory Tracking来获取有关线程的一般信息,但我不确定如何单独获取有关每个线程的信息。
启动应用程序时,将
-XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics
添加到vm选项中:现在,如果运行:
在你的机器上找到java进程
您将看到如下所示的内容:
有了这个信息,你可以用19126 KB/159= 120 KB来得到每个线程的平均内存大小,问题是这样做不会单独告诉你每个线程,一些线程会更大,另一些会更小。
您还可以用途:
这将告诉您基线时刻和高峰流量期间可以进行的跑步之间的差异。