JVM内存结构
一、程序计数器
1.定义
Program Counter Register 程序计数器(寄存器)
2.作用
背景:java源代码-JVM指令-解释器-机器码
程序计数器会记住下一条JVM指令的执行地址
3.实现
硬件:寄存器
4.特点
- 每个线程都有自己程序计数器(线程私有)
- 不会存在内存溢出
二、虚拟机栈
1.定义
-
每个线程运行时都需要的内存空间(线程私有)。
-
栈由栈帧组成,栈帧调用不同的方法所占用的内存。
(idea中的frames可以演示栈帧的变化)
2.栈内存溢出
(1)栈帧过多导致占内存溢出
错误的递归调用
对象转json字符串时,存在类间的双向引用(死循环)
(2)栈帧过大导致栈内存溢出
3.线程运行诊断
(1)CPU占用过高
- top --定位线程占用cpu的情况
- ps H -eo pid,tid,%cpu|grep pid --查询线程的占用情况
- jstack pid
- 根据pid找到有问题的线程,进一步定位到问题代码的源码行号
(2)死锁情况
线程1锁住了线程2的A锁;线程2锁住了线程1的B锁
4.注意点
(1)垃圾回收是否涉及栈内存?
不需要。栈内存是方法的调用,调用结束后即出栈
(2)栈内存分配越大越好码?
不是。由定义可知:栈内存是单个线程运行的空间,总空间一定时,栈内存越大,容纳的线程数越少。
(3)方法内的局部变量是否线程安全?
是。栈是线程私有的,相当于每次都new出一个方法进入不同的栈。
(4)哪些变量是线程不安全的?
有可能被其他线程访问到的变量。
三、本地方法栈
概念
- 不是java编写的底层方法(native)使用的内存空间。
四、堆
1.定义
- 通过new关键字创建的对象都会使用堆内存(共享)
2.特点
线程共享 ——因此需考虑线程安全问题
有垃圾回收机制 --System.gc()
3.堆内存溢出
出现溢出的原因
- 那些本该回收的对象,仍然被使用着,当规模达到一定程度,则出现溢出。(OutOfMemoryError)