Java JFR 民间指南 - 事件详解 - jdk.ThreadAllocationStatistics (8)

这个 native 方法对应的 JVM 源码是:
ThreadImpl.c

JNIEXPORT jlong JNICALL Java_sun_management_ThreadImpl_getThreadAllocatedMemory0 (JNIEnv *env, jclass cls, jlong tid) { //实际实现方法是 GetOneThreadAllocatedMemory return jmm_interface->GetOneThreadAllocatedMemory(env, tid); }

management.cpp

JVM_ENTRY(jlong, jmm_GetOneThreadAllocatedMemory(JNIEnv *env, jlong thread_id)) if (thread_id < 0) { THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "Invalid thread ID", -1); } //获取当前线程 if (thread_id == 0) { // current thread //调用 cooked_allocated_bytes,和采集 jdk.ThreadAllocationStatistics 调用的底层方法一样 return thread->cooked_allocated_bytes(); } //根据线程号获取线程 ThreadsListHandle tlh; JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id); if (java_thread != NULL) { //调用 cooked_allocated_bytes,和采集 jdk.ThreadAllocationStatistics 调用的底层方法一样 return java_thread->cooked_allocated_bytes(); } return -1; JVM_END

可以看出,其实底层调用的和 JFR 采集 jdk.ThreadAllocationStatistics 事件一样,都是调用 Thread 的 cooked_allocated_bytes() 方法。

针对这个 JFR 事件的一些思考

首先,提出一个观点,jdk.ThreadAllocationStatistics 这个事件并不太消耗性能。原因有二:

统计线程分配大小是近似统计,并不需要进入全局安全点统计。同时也代表,jdk.ThreadAllocationStatistics 同一时间的不同线程事件的分配大小实际并不是同一时间点的,因为没有进入安全点暂停所有线程

统计仅仅是原子读取每个线程的分配对象大小这个变量,之后加上每个线程当前 TLAB 分配对象大小(这个大小是通过读取两个指针地址获取的),可以看出操作是很轻量级的。即使有很多线程,也不会增加多少性能负担

然后,默认配置的采集周期,并不能满足我们的需求。默认的采集周期是 everyChunk,默认的 chunk 大小(maxchunksize)是 12M,也就是每采集 12M 的 JFR 事件之后,采集一次 jdk.ThreadAllocationStatistics。这是不太可控的,我一般配置为每过 5s 采集一次。这样对于我们上面提到的那两个需要这个事件的场景也是很适合的。

微信搜索“我的编程喵”关注公众号,加作者微信,每日一刷,轻松提升技术,斩获各种offer

image

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydpxz.html