引言
常见的JVM
学习路线
jvm内存结构
1. 程序计数器
1.1 定义
Program Counter Register程序计数器(寄存器)
可以看做是当前线程所执行的字节码的行号指示器,字节码解释器的工作时就是通过改变这个计数器的值来选取下一条执行的字节码指令
特点
- 线程私有的(因为每个线程执行的程序是不一样的)
- 不会内存溢出
1.2 作用
程序计数实际上是由寄存器来实现的
2. 虚拟机栈
线程私有,且生命周期线程相同,每个方法运行时java虚拟机都会同步创建一个栈帧用于存储局部变量表,也就是栈帧是每个方法运行时需要的内存,比如方法的变,返回值等
2.1 定义
- 每个线程运行时需要的内存,成为虚拟机栈
- 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
- 每个线程只能有一个活动栈,对于着当前正在执行的方法
栈的默认大小
问题
- 垃圾回收是否涉及栈内存?
不涉及,因为每次方法运行结束栈帧会自动弹出 - 栈内存分配的越大越好吗
不会,栈内存越多那么,线程数目会越少 - 方法内的局部变量是否线程安全
- 局部变量是局部私有的,但是如果static会有线程安全问ti
- 如果局部变量引用了对象,并逃离了该方法的作用范围也是不安全的
两个线程都会修改同一个StringBuilder对象
这里返回了说明其他线程也会拿到该对象进行修改,也不安全
2.2 栈内存溢出
- 帧过多导致栈溢出(递归)
- 栈帧过大
2.3 线程运行诊断
案例一,cpu占用过高
定位
- 用top定位哪个进程对cpu占用过高
ps H -eo pid,tid,%cpu | grep 进程id
可以查看进程内的线程的cpu占用
- jstack 进程id
- 可以根据线程id找到有问题的线程,进一步找到问题代码的行号
案例二, 迟迟不到结果
找到死锁
3. 本地方法栈
就是c/c++ 编写的方法和系统底层打交道