JVM
2020-04-27 15:27:40 2 举报
AI智能生成
JVM知识系统整理(制作不易,求个赞)
作者其他创作
大纲/内容
JVM
运行时数据区域
线程独占
程序计数器
功能:记录程序运行的行号。
唯一不会oom的区域。
虚拟机栈和本地方法栈
功能:用于描述Java方法执行时的内存模型,存放的数据结构是栈帧。
线程创建过多时,会OOM或者StackOverFlow
可以通过 -Xss 来调节栈的大小
线程共享
堆
功能:存放对象实例。字符串常量和静态变量。
会OOM。
是GC的重点处理区域。
可以通过-Xms和-Xmx来调节最小和最大堆内存。
方法区
元空间
功能:负责存放已加载的类信息、方法信息、JIT代码缓存、运行时常量池和运行期间生成的代理类信息。
可以通过 -XX:MaxMetaspaceSize 来设定最大元空间。
可以通过 -XX:MetaspaceSize 来设定默认元空间大小。
运行时常量池,方法区的一部分。
功能:在类加载结束后将Class文件中常量池内容存放到运行时常量池。
会OOM
直接内存
直接内存并不是虚拟机运行时数据区的一部分
会受到本机总内存大小,也有可能OOM
可以通过 -XX:MaxDirectMemorySize 来调解直接内存大小。
对象的创建、内存布局和定位
对象的创建过程。有五步
1、类加载
2、在堆中为对象分配内存空间。依据GC是否具有空间压缩功能,分配方法有两种:
1、指针碰撞法
2、空闲列表法
3、将对象中属性初始化为0值。不包含对象头设置
4、将对象进行设置,主要是对象头设置。包括此对象所属的类元数据信息,hashCode,GC分代年龄等
5、执行Class文件中的<init>方法。即构造函数。
JVM是如何保证多线程内存分配的安全性的?
CAS + 失败重试
TLAB。本地线程分配缓冲区。
对象的内存布局
对象头
MarkWord。存储自身运行时的数据
锁信息。锁标志位,指向ObjectMonitor对象的指针。
hashCode值。
GC分代年龄
类型指针。
指向Class对象的指针
实体数据
对齐填充
对象的访问定位
句柄访问
优点:对象移动时,引用不变。
缺点:两次寻址。
直接访问
优点:一次寻址,速度快。
缺点:对象移动时,引用变化。
内存分配和垃圾回收
对象是否死亡?
引用计数法
可达性分析法
GC Roots有哪些对象?
1、虚拟机栈中所引用的对象
2、方法区中静态属性所引用的对象
3、方法区中常量属性引用的对象
4、本地方法栈中所引用的对象
再谈引用
强引用
软引用
弱引用
虚引用
使用场景有哪些?
主要用来跟踪对象被垃圾回收的活动
垃圾回收算法
方法区回收
废弃的常量
不使用的Class对象。回收条件:
1、该类的对象都已经被回收。
2、加载该类的ClassLoader被回收。
3、Class对象没有在任何地方被使用。
堆内存分代收集理论
Minor GC
只对新生代内存区域进行回收。
Major GC
只对老年代内存区域进行回收。目前只有CMS收集器会有单独收集老年代的行为。
Mixed GC
指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。
Full GC
对整个Java堆和方法区的垃圾收集。
算法
标记清除
阶段1:标记所有死亡的对象,或者反着来,标记活着的对象。阶段2:清除死亡对象。
存在的问题
1、随着对象数量变多,效率低。
2、会产生大量不连续的内存碎片。
针对新生代,标记复制
将内存划分为相等的两块,每次只使用一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
1、空间浪费
Appel式回收
分为Eden和2个Survivor。默认只浪费10%空间。
标记整理
让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。
算法总结
权衡
1、当有大量对象时,移动和复制的问题。
2、内存碎片化的问题。
和稀泥
经典垃圾回收器
Serial
特点
1、最基础,历史悠久的收集器。
2、没有线程交互开销,简单而高效。对于内存资源和处理器资源受限的场景,开销最小。
3、单线程串行化收集,会暂停用户线程。stop the world梗也是从这里来的。
收集区域
新生代。
标记--复制
缺点
用户线程的短暂停顿。
Serial old
Serial收集器的老年代版本。使用标记-整理算法。
ParNew
是 Serial 收集器的多线程版本,其余和Serial一样。
Parallel Scavenge
看上去几乎和ParNew都一样,但重点关注达到一个可控制的吞吐量。
最大垃圾收集停顿时间的-XX:MaxGCPauseMillis
直接设置吞吐量大小的-XX:GCTimeRatio参数
自适应调节:-XX:+UseAdaptiveSizePolicy参数
新生代
侧重于吞吐量
Parallel Old
Parallel Scavenge的老年代版本。标记--整理
CMS
1、低停顿。一种以获取最短回收停顿时间为目标的收集器。几乎能做到和用户线程同时工作。
2、并发收集。第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
老年代
标记--清除,达到碎片化阈值时,执行标记整理。
CPU敏感,会产生大量内存碎片
G1
类加载过程
类加载步骤
1、加载
读取二进制文件(后缀名为.class的文件)。
2、链接
验证
类文件的正确性。
准备
为类中静态变量划分内存,并初始化为默认值。
解析
将类中的符号引用转化为直接引用。
3、初始化
为类的静态变量赋予正确的初始值。
主动使用导致类初始化
1、使用new关键字
2、设置或读取了静态变量
3、调用了类中的静态方法
4、反射了某个类
5、当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
6、执行Main方法时,会初始化启动类。
被动使用不导致初始化
1、通过子类直接访问父类的静态变量,只会导致父类初始化,子类并不会初始化。
2、定义引用数组也不会导致类初始化的
3、读取被定义为final的常量也不会导致类初始化
类加载器种类
1、根加载器
加载核心类库,比如lang包
没有父加载器,实现依赖于底层操作系统
2、扩展类加载器
加载/lib/ext目录下扩展jar包。
父加载器是根加载器。
3、系统类(应用类)加载器
加载classpath中的jar包。
父加载器是扩展类加载器。
双亲委派机制
机制
父委托机制是将类的加载优先交给父加载器去尝试加载,如果父加载器无法加载,再一级一级的交给子加载器进行加载。
好处
防止自定义的类加载器来加载应该由父加载器来加载的恶意代码。
破坏机制--驱动加载
类卸载
1、所有的实例都已经被GC
2、加载该类的ClassLoader被回收
3、该类的Class对象没有在任何地方被使用
线程上下文类加载器
JDK提供的监控工具
jps
虚拟机进程
jmap
堆转储快照
jstack
堆栈跟踪
jConsole
jVisualVM
JVM参数整理
参数分类
\"-\"
标准参数(-):所有的JVM实现都必须实现这些参数的功能,而且要向后兼容。
\"-X\"
子主题
\"-XX\"
参数详细
0 条评论
回复 删除
下一页