垃圾收集器与内存分配策略
垃圾收集器(GC [grabage collection])
GC做了什么事情
-
哪些内存需要回收
- 虚拟机栈,本地方法栈,程序计数器是属于线程私有的,随着线程创建而分配内存,线程结束自动清除。
- java堆和方法区
-
什么时候回收
-
堆
-
堆中存放的是JAVA创建的实例对象,因此在回收之前必须确定哪些对象是“存活的”,哪些对象是“死亡的”,回收的时候,回收的就是“死亡对象”;
-
判断方法有两种:
-
引用计数法
给对象一个引用计数器,每引用一次,计数器加1,失效的时候减1.只要引用计数器的值为0的时候,则说明该对象不会被使用了,进入“死亡”状态。就表示可以回收了。
缺点:不能解决循环依赖
-
可达性分析法
通过GC Roots作为起点开始往下搜索,当一个对象到GC Roots没有任何引用链的时候,则该对象不可达,那么就判定其为可回收对象。
那么GC Roots是什么?
可以作为GC Roots的对象包括四种,
- 虚拟机栈中的引用对象
- 方法区中静态变量引用的对象
- 方法区中常量引用的对象
- 本地方法栈中引用的对象
引用分为四种
引用类型 被回收时间 用途 生存时间 强引用 从来不会 对象的一般状态 JVM停止运行时 软引用 内存不足时 对象缓存 内存不足时 弱引用 jvm垃圾回收时 对象缓存 gc运行后 虚引用 未知 未知 未知
-
-
方法区
-
一般不要求对方法去的垃圾进行回收,复杂度比较高,
-
怎么回收
运用各种垃圾收集算法
- 标记清除算法
- 标记整理算法
- 复制算法
- 分代收集算法
垃圾收集器
串行收集器
并行收集器
-
年轻代
- serial
最古老的,单线程的收集器,采用复制算法
开启Serial收集器:-XX:+UseSerialGC, 与Serial Old搭配使用的运行过程如下图
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWFnZXMyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM1MDg0My8yMDE4MDcvMTM1MDg0My0yMDE4MDcwNDA3NDIzMzIxMC0xODcxMjQ3ODI4LnBuZw?x-oss-process=image/format,png)
- parNew
相当于Serial的多线程版本,采用复制算法
开启方式:选择CMS(-XX:+UseConcMarkSweepGC)后默认的新生代收集器是ParNew,也可用-XX:+UseParNewGC命令指定为ParNew收集器。
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWFnZXMyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM1MDg0My8yMDE4MDcvMTM1MDg0My0yMDE4MDcwNDA4MDUwNTk0MS0xODk5MTExMDg1LnBuZw?x-oss-process=image/format,png)
- parallel Scavenge
多线程,并行的垃圾收集器,采用的算法是复制算法
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWFnZXMyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM1MDg0My8yMDE4MDcvMTM1MDg0My0yMDE4MDcwNDIwMjkwNjQ2NC0xMzEyNzM5NzM2LnBuZw?x-oss-process=image/format,png)
-
老年代
- serial Old
单线程的垃圾收集器,采用标记整理算法
- Parallel Old
多线程的收集器,采用标记整理算法,注重吞吐量。
- CMS
采用标记清除算法,STW时间短,并发收集
收集过程
- 初始标记,会进行STW,在初始标记的时候只会标记GC Roots能够关联的对象,速度快。
- 并发标记
- 重新标记:修正并发标记期间因为用户线程继续运行而导致的标记产生变动的那一部分对象的标记记录。
- 并发清除。
CMS收集器的内存回收过程是与用户线程并发执行的。
缺点:
- 对CPU资源敏感
- CMS采用的是标记清除算法,造成大量的内存碎片对分配大对象不利
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWFnZXMyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM1MDg0My8yMDE4MDcvMTM1MDg0My0yMDE4MDcwNDIxNTA1NDc2Mi0yMTQxMjAxOTA5LnBuZw?x-oss-process=image/format,png)
G1收集器