JVM源码系列:ThreadMXBean 打出堆栈信息原理分析
我们通常会使用工具jstack 去跟踪线程信息,其如何实现使用attach 的方式还是ptrace 的方式,这些可以去参考本人的博客的其他文章。
但这些方式都是外部使用的方式,如何直接使用java代码得到当前进程的线程的信息,方便监控jvm的整个运行状态,就不的不提到了ManagementFactory
通过调用方法
ThreadMXBean tmbean = ManagementFactory.getThreadMXBean();
通过得到 ThreadMXBean 可以得到非常多的thread信息,博客里也主要提到几个重要函数的实现
ThreadMXBean是个接口,主要实现都是在 ThreadImpl.java 里实现。
1. getThreadCount()
在虚拟机里会有ThreadService,里面会有些计数器用于记录总线程数,活着线程数目
-
PerfCounter* ThreadService::_total_threads_count = NULL;
-
PerfVariable* ThreadService::_live_threads_count = NULL;
-
PerfVariable* ThreadService::_peak_threads_count = NULL;
-
PerfVariable* ThreadService::_daemon_threads_count = NULL;
-
volatile int ThreadService::_exiting_threads_count = 0;
-
volatile int ThreadService::_exiting_daemon_threads_count = 0;
当线程创建,消亡都会调用 ThreadService 的方法来对计数器加减,这样就能直接得到线程数目的状态,而不需要去遍历线程链表。
2. getAllThreadIds()
这个实现也比较简单,直接扫描线程列表,就可以得到每个java 的线程id, 在扫描过程中使用了锁,锁住了线程链表。 但因为从native代码到java代码中没有锁结构,得到线程的列表只能表示当时的状态,当得到id的时候并不能保证该线程依然存活。
-
ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread,
-
bool include_jvmti_agent_threads,
-
bool include_jni_attaching_threads) {
-
assert(cur_thread == Thread::current(), "Check current thread");
-
-
int init_size = ThreadService::get_live_thread_count();
-
_threads_array = new GrowableArray<instanceHandle>(init_size);
-
-
MutexLockerEx ml(Threads_lock);
-
-
for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) {
-
// skips JavaThreads in the process of exiting
-
// and also skips VM internal JavaThreads
-
// Threads in _thread_new or _thread_new_trans state are included.
-
// i.e. threads have been started but not yet running.
-
if (jt->threadObj() == NULL ||
-
jt->is_exiting() ||
-
!java_lang_Thread::is_alive(jt->threadObj()) ||
-
jt->is_hidden_from_external_view()) {
-
continue;
-
}
-
-
// skip agent threads
-
if (!include_jvmti_agent_threads && jt->is_jvmti_agent_thread()) {
-
continue;
-
}
-
-
// skip jni threads in the process of attaching
-
if (!include_jni_attaching_threads && jt->is_attaching()) {
-
continue;
-
}
-
-
instanceHandle h(cur_thread, (instanceOop) jt->threadObj());
-
_threads_array->append(h);
-
}
-
}
我们也可以看到 JNI attach 的线程,和jvmti agent的线程是不被统计在内的
3. ThreadInfo[] getThreadInfo 得到线程具体的堆栈信息
不论是传入要取的线程列表还是要取的所有的线程列表,最后都会看到将取堆栈信息的任务交给了vm thread 线程处理,关于vm thread的作用可以参考本人的其他博客。
-
// Obtain thread dumps and thread snapshot information
-
VM_ThreadDump op(dump_result,
-
thread_handle_array,
-
num_threads,
-
max_depth, /* stack depth */
-
with_locked_monitors,
-
with_locked_synchronizers);
-
VMThread::execute(&op);
a. vm thread 去遍历所有线程的信息,由于是单线程处理,如果线程数量多的话是会影响到性能的,因为在扫描堆栈过程中,是在softpoint的状态。
b. ThreadDumpResult dump_result(num_threads); 使用ThreadDumpResult 去存储ThreadSnapshot 而保证不会被gc,因为从vm thread抓取线程结束,在填充threadinfo的时候还是会发生gc。
4. 锁的细节显示
在函数 dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers)里有2个参数 lockedMonitor, 和 lockedSynchronizer
而这两个参数分别控制两种锁ThreadInfo .getLockedMonitors() 和 ThreadInfo.getLockedSynchronizers()
a. Monitor 锁
就是我们传统使用的synchronized(Object obj),
可以通过MonitorInfo[]得到具体的锁的数量和信息
b. Locked ownable synchronizers 锁
常指的ReentrantLock 和 ReentrantReadWriteLock 锁
通过得到LockInfo[] 可以得到具体的类,锁的数量和信息
JVM源码系列:ThreadMXBean 打出堆栈信息原理分析的更多相关文章
- Mybaits 源码解析 (五)----- 面试源码系列:Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)
刚开始使用Mybaits的同学有没有这样的疑惑,为什么我们没有编写Mapper的实现类,却能调用Mapper的方法呢?本篇文章我带大家一起来解决这个疑问 上一篇文章我们获取到了DefaultSqlSe ...
- Spring源码系列 — 注解原理
前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...
- Spring源码系列 — BeanDefinition
一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...
- 事件机制-Spring 源码系列(4)
事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...
- Ioc容器BeanPostProcessor-Spring 源码系列(3)
Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...
- JVM源码分析之Metaspace解密
概述 metaspace,顾名思义,元数据空间,专门用来存元数据的,它是jdk8里特有的数据结构用来替代perm,这块空间很有自己的特点,前段时间公司这块的问题太多了,主要是因为升级了中间件所 ...
- 9 hbase源码系列(九)StoreFile存储格式
hbase源码系列(九)StoreFile存储格式 从这一章开始要讲Region Server这块的了,但是在讲Region Server这块之前得讲一下StoreFile,否则后面的不好讲下去 ...
- 从jvm源码看synchronized
从jvm源码看synchronized 索引 synchronized的使用 修饰实例方法 修饰静态方法 修饰代码块 总结 Synchronzied的底层原理 对象头和内置锁(ObjectMonito ...
- JVM源码分析-JVM源码编译与调试
要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...
随机推荐
- MFC只允许程序单开
很多玩游戏的人都知道一般游戏客户端程序是不允许双开的,就是说在同一游戏在启动的时候,是无法打开多个窗口.很多其他软件如酷狗播放器等也是这样.如果把打开的窗口最小化,这时重新启动程序,最小化的窗口会被显 ...
- ArcEngine的ToolbarControl解析
转自Love Lyre原文 ArcEngine的ToolbarControl解析 ToolbarControlClass有三个主要的接口: IToolbarControl, IToolbarContr ...
- android-铃声的设置与播放
在android系统中,不同铃声存放的铃声路径: /system/media/audio/ringtones 来电铃声 /system/media/audio/notifications 短信通知铃声 ...
- 如何从mysql数据库中取到随机的记录
如何从mysql数据库中取到随机的记录 一.总结 一句话总结:用随机函数newID(),select top N * from table_name order by newid() ----N是一个 ...
- 存储过程和SQL语句比较
做为SQL存储过程和.NET的新手,下面的指导还是很有用的,自己这一段刚刚接触这些东西,搜集了一些相关的东西,能使新手较容易上手,当然啦,要精通和熟练应用,还是要看更多更深的资料的,高手请不要见笑.以 ...
- GO语言学习(十四)Go 语言数组
Go 语言数组 Go 语言提供了数组类型的数据结构. 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 相对于去声明number0 ...
- Fragment Summary 2/2
出处:http://blog.csdn.net/lmj623565791/article/details/37992017 上篇博客中已经介绍了Fragment产生原因,以及一些基本的用法和各种API ...
- IR_drop
IR压降是指出现在集成电路中电源和地网络上电压下降或升高的一种现象.随着半导体工艺的演进金属互连线的宽度越来越窄,导致它的电阻值上升,所以在整个芯片范围内将存在一定的IR压降.IR压降的大小决定于从电 ...
- java中Arrays类的应用
java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的.具有以下功能: ² 给数组赋值:通过fill方法. ² 对数组排序:通过sort方法,按升序. ² 比较数组:通过equ ...
- Java BigDecimal的基本使用方法
1.对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类 2.运算速度比一般的+.-.*./要快 3.基本方 法描 述 ...