1.程序计数器(Program Counter Register)
1-1.作用
记住下一条jvm指令的执行地址
1-2.特点
①.线程私有
②.不存在内存溢出
2.虚拟机栈(Java Virtual Machine Stack)
2-1.定义
每个线程运行时需要的内存空间
组成内容:栈帧(每个方法运行时需要的内存;对应方法的调用)
每个线栈只能有一个活动栈帧(线程正在执行的方法),对应着当前正在执行的那个方法
问题解析:
①.垃圾回收不涉及栈内存
②.栈内存不是越大越好
③.线程共享需要考虑线程安全,线程私有不需要考虑线程安全;如果方法内局部变量没有逃离方法的作用范围就是线程安全的,当作返回值就需要保护;如果局部变量引用了对象,并逃离了方法的作用方法,需要考虑线程安全
2-2.栈内存溢出
①.栈帧过多导致栈内存溢出
②.栈帧过大导致栈内存溢出
2-3.线程运行诊断
①.cpu占用过多
定位:
A.top定位哪个进程对cpu的占用过高
B.[ps H -eo pid,tid,%cpu|grep进程id(用ps命令进一步定位哪个线程引用的cpu占用过高)];
C.jstack进程id(根据线程id找到有问题的线程,进一步定位到问题代码的源码行数)
②.程序运行很长时间没有结果
3.本地方法栈(Native Method Stacks)
定义:为本地方法的运行提供一个内存空间
4.堆(Heap)
4-1.定义
通过new关键字,创建对象都会使用堆内存
4-2.特点
它是线程共享的,堆中对象都需要考虑线程安全问题
有垃圾回收机制
4-3.堆内存的溢出
内存过大时,不容易暴露内存溢出;排查堆内存问题时,把内存的值设置小一点
4-4.堆内存诊断
①.jps工具
查看当前系统中有哪些java进程
②.jmap工具
查看堆内存占用情况(加上 -heap进程id )
③.jconsole工具
图形界面的,多功能检测工具,可以连续检测
垃圾回收后,内存占用依然很高
jvisualvm与jconsole相似
5.方法区
5-1.定义
是JVM线程的方法共享区,存储和类结构相关的信息,包括:成员变量、方法数据、成员和构造器代码和运行时常量池
方法区在虚拟机启动时创建;逻辑上,方法区是堆的组成部分;规范不强制执行用于管理编译代码的方法区
5-2.组成
5-3.方法区内存溢出
1.8之前会导致永久代内存溢出
演示永久代内存溢出:java.lang.OutOfMemoryError:PermGen space
-XX:MaxPermSize=8m
1.8之后会导致元空间内存溢出
演示元空间内存溢出:java.lang.OutOfMemoryError:Metaspace
-XX:MatespaceSize=8m
应用场景:
①.spring
②.mybatis
5-4.运行时常量池
常量池:是一张表,虚拟机根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息(给指令提供一些常量符号,以查表的方式查找)
运行时常量池:是.class文件中的,当被类加载,它的常量池信息会被放入运行时常量池,并把里面的符号地址变为真实地址
5-5.StringTable特性
①.常量池中的字符串仅是符号,第一次用到时才变为对象
②.利用串池的机制,避免重复创建字符串对象
③.字符串变量拼接的原理是StringBuilder(1.8)
④.字符串常量拼接的原理是编译期优化
⑤.可以使用intern方法,主动将串池中还没有的字符串对象放入串池
5-6.StringTable位置
①.1.8用的是堆空间
②.1.6用的是永久代
5-7.StringTable垃圾回收
5-8.StringTable性能调优
①.调整-XX:StringTableSize=桶个数
②.考虑将字符串对象是否入池
6.直接内存
6-1.定义
①.常见于NIO操作时,用于数据缓冲区
②.分配回收成本较高,但读写性能高
③.不受JVM内存回收管理
6-2.分配和回收原理
①.使用Unsafe对象完成直接内存的分配回收,并且回收需要主动调用freeMemory方法
②.ByteBuffer的实现类内部,使用了Cleaner(虚引用)来检测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过Cleaner的方法调用freeMemory来释放直接内存