JVM详解
jdk
jdk包含jre(Java运行时环境)+内部命令(如:javap、javac等)
jvm由哪几部分组成
什么是类加载
类加载是指将Main.class文件中的二进制数据读入内存中,并将其放在运行时数据区的方法区内,然后在堆区中创建一个class对象
类加载过程
- 加载:通过IO读入字节码文件
- 连接:验证、准备、解析
- 初始化:对类的静态变量初始化、执行静态代码块
- 使用
- 卸载
类加载器的种类
- 启动类加载器:负责加载JRE的lib目录下的核心类库,如rt.jar、charsets.jar等
- 扩展类加载器:负责加载JRE的lib目录下ext扩展目录中的jre类包
- 应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类包
- 自定义类加载器:加载用户自定义路劲下的类包
Java虚拟机运行时内存区域划分
线程是否私有
-
线程私有区域:
- 程序计数器:记录字节码执行的行号,java虚拟机中唯一不会产生内存溢出的地方
- 虚拟机栈:java中方法执行时形成栈帧压入虚拟机栈称为压栈,方法执行完栈内存弹出称为弹栈,栈帧分为局部变量表、操作数栈、动态链接、方法出口、附加信息
- 本地方法栈
-
线程共有区域:
- 堆内存:分配所有对象实例的地方,垃圾回收的主要区域,所有内存中最大的一块
- 堆内存的划分:年轻代(Eden、From、To),老年代
- 元数据区(方法区):虚拟机加载的类信息、常量、静态变量
- 直接内存:堆外内存,由NIO操作,效率高
JVM分配与回收策略
分配策略
-
对象优先分配在Eden区,当空间不足时发起MinorGc
-
大对象直接进入老年代(如:字符串、数组)
- 为了避免大对象分配内存时赋值操作而降低效率
-
长期存活的对象将进入老年代(虚拟机给每个对象一个年龄计数器Age,对象每熬过一次MinorGC Age+1,默认当Age=15晋升到老年代)
-
MinorGC后存活的对象Survivor放不下部分直接进入老年代
-
Eden区与Survivor区默认比例8:1:1
-
老年代空间分配担保机制,FullGC回收完还是没有足够空间存放新的对象就会发生OOM
-
对象动态年龄判断,Survivor区对象年龄总和超过Survivor区的50%,那么大于等于这批对象年龄最大值的对象直接进入老年代(这个规则是希望可能长期存活的对象尽早进入老年代)
-
(年龄1+年龄2+…+年龄n)>50%,年龄n以上的都进入老年代
-
对象动态年龄判断机制一般在minor GC后触发
MinorGc与FullGc区别:
- MinorGC:指发生在新生代的垃圾回收动作,非常频繁,回收速度快
- FullGC:回收老年代、年轻代、方法区的垃圾,比MinorGc慢十倍以上
java虚拟机如何判断对象是否存活
- 引用计数法:对象的引用计数器为0时,即无其他对象引用判定为死亡,可被回收,但是存在循环引用问题,导致对象一直存活
- 可达性分析法:从GCRoot根开始向下搜索,可直接或间接可达的对象存活
- 哪些对象可做GCRoot对象:虚拟机栈引用对象、本地方法栈引用对象、静态属性引用对象、常量引用对象
对象引用分类
1.强引用:
程序中普遍存在的对象引用,只要存活就不会被回收,即使内存溢出。
2.软引用:
SoftReference实现,内存溢出前回收。
3.弱引用:
WeakReference实现,下一次垃圾回收时回收。
4.虚引用:
PhantomReference实现,形同虚设。
垃圾回收算法(内存回收的方法论)
1.标记清除算法
先标记出所有需要回收的对象, 标记完成后统一回收,产生大量不连续的内存碎片,当有大对象要分配时,有可能再次触发垃圾回收。
2.标记整理算法
在标记清楚的基础上,回收后集中整理内存区域,避免产生大量碎片内存,但效率降低。
3.复制算法
将内存划分为相同大小的两块,每次使用其中一块,当这块部分使用完,将其中存活的对象复制到另一块,将使用过的空间一次性清除
优点:效率高、没有碎片、适合朝生夕死的内存区域。
缺点:内存利用率低,不适合对象存活率较高的老年代
4.分代回收算法
新生代:复制算法
老年代:标记清楚/整理
垃圾收集器(内存回收的具体体现)
1.Serial收集器和Serial Old收集器
单线程收集器,会Stop the word
新生代:复制算法
老年代:标记清整理算法
优点:
简单高效(很高的单线程收集效率)
serial old收集器 :serial的老年代版本
2.ParNew收集器
serial收集器的多线程版本
默认线程数与CPU核数相同
3.Parallel Scavenger收集器(与Par New类似)
老年代版本:Parallel Old
新生代:复制算法
老年代:标记清整理算法
特别:
关注点(吞吐量) 高效率的利用CPU
吞吐量:运行代码时间:CPU总运行时间
4.CMS收集器(Conrrurent Mark Sweep)
目标:获取最短回收停顿时间
算法:标记—清除
运作过程:
- 初始标记:标记GCRoot能直接关联的对象(单线程)
- 并发标记:用一个闭包结构去记录可达对象(占用70%-80%时间)
- 重新标记:修正并发标记期间因为用户程序继续运作发生变动的那部分对象的标记记录
- 并发清除
优点:
并发收集、低停顿
缺点:
- 对CPU资源敏感会和服务器抢资源
- 无法处理浮动垃圾
- 标记—清除算法产生大量内存碎片
- 执行过程的不确定性,存在上一次垃圾回收没有回收完,垃圾回收再次触发的情景
G1(Garbage-First)收集器
一款面向服务器的垃圾收集器(主要针对面向多颗处理器及大容量内存的机器)高概率满足GC停顿时间的同时,还具备高吞吐量。
特点:
- G1将堆划分为多个大小相等的独立区域(Region)最多2048个Region。
- 一般Region大小等于堆大小除以2048。
- G1保留年轻代与老年代,不在物理隔阂,都是(可以不连续)Region集合。
- 默认年轻代占堆的5%。
- Region区域功能动态变化
- G1有专门存储大对象的Region Humongous区(当一个对象超过Region的50%为大对象)
G1垃圾回收过程
- 初始标记:暂停所有其他线程,并记录GCRoot直接引用对象
- 并发标记:用一个闭包结构记录可达对象,跟踪记录引用更新的地方。
- 最终标记:修正并发标记期间因用户进程运作而导致标记产生变动的那一部分对象的标记记录
- 筛选回收:先对各个Region回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划。