JVM Stack 栈 和 程序计数器| 豆包MarsCode AI刷题

32 阅读3分钟

Stack栈

概念:

栈:每个线程运行时需要的内存空间,虚拟机栈

每个栈中有一个一个的栈帧

栈帧:每个方法运行时需要的内存 (里面有一个局部变量表)

每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

问题辨析

1、垃圾回收是否涉及栈内存:不涉及,栈帧直接出栈,局部变量那个都无了

2、栈内存分配越大越好嘛?不是 ,不会增加执行效率,会减少线程数

栈内存大的好处是:可以进行更多次的递归调用

栈内存通过虚拟机参数进行指定,-Xss size

线程数会变少,物理内存大小固定

3、方法内的局部变量是否线程安全:

如果方法内局部变量没有逃离方法的作用范围,它是线程安全的

如果局部变量引用了对象,并逃离了方法的作用范围,需要考虑线程安全

栈内存溢出

1、栈帧过多导致栈内存溢出(递归调用,没有正确的条件)

或者两个对象相互引用,然后转换的时候出现递归,通过@JsonIgnore忽略相互调用的对象

2、栈帧过大导致栈内存溢出(不太容易出现)

线程运行诊断

案例1:cpu占用过多

定位:

1、用top定位那个进程对cpu的占用过高

2、ps -H -eo pid,tid,%cpu | grep 进程id(用ps命令进一步定位是那个线程引起的cpu占用过高)

3、jstack进程id

可以根据线程id找到有问题的线程,进一步定位到有问题代码的源码行数

案例2:程序运行很长时间都没有结果:可能因为多个线程死锁导致

程序计数器

Java源代码——》 JVM指令(二进制字节码)——》解释器 ——》机器码——》CPU

程序计数器作用(寄存器==cpu中读取速度最快的单元,因为读取很频繁):记住下一条JVM指令的执行地址

解析器去程序计数器中取指令

特点:

线程私有(每一个线程都有各自的程序计数器,存自己线程运行时的下一个条执行地址)

不会存在内存溢出(因为指令的地址大小是固定的)

##Heap 堆 通过new关键字创建对象都会使用堆内存

特点:

是线程共享的,堆中对象都需要考虑线程安全的问题

有垃圾回收机制(当对象没有被引用,会被回收掉)

堆内存溢出OutOfMemoryError:当变量超级大,而且没有被回收时

堆内存的大小设置:-Xmx size

堆内存诊断(直接内存使用情况看不了,因为不受JVM管理)

1、jps工具:查看当前系统中有哪些java进程

2、jmap工具:查看堆内存占用情况 : jmap -heap 进程号

3、jconsole工具,多功能的检测工具,可以连续检测

4、jvisualvm工具,可视化工具(更好用,可以抓取某一个时刻堆中对象的大小占用情况dump命令)

案例

垃圾回收后,内存占用仍然很高

通过jmap工具抓取程序快照存入一个文件1.bin

jmap -dump:format=b,live,file=1.bin 进程号