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 进程号