1.内存分配
参数:
新生代:-Xmn
堆空间:-Xms: 最大 ; -Xmx: 最小;
常见分配策略
- 1)对象优先分配在Eden区;
- 2)大对象直接进入老年代;
- 3)长期存活的对象将进入老年代;
2. 回收机制
Full Gc
收集整个堆,包括新生代、老年、方法区;
触发条件
1)当需要在老年代分配内存空间,但没有足够的空间时;
2)System.gc();
3)触发Minor Gc 时,发现转移的空间 比 向老年代的大;
Minor Gc
收集新生代的垃圾
触发条件
Eden区空间耗尽时;
过程
当发生MinorGc时,Eden区和From s区存活的对象会被复制到 To s 区,然后 From s 和 From t 指针交换,保证 To s区 是空的;
Survivor区对象晋升位老年代对象的条件
当在 From s 和 To s去 被来回复制15次,会被扔到老年代;
3.判定对象已死?
引用计数法
给对象添加引用计数器,有地方引用+1,引用失效就-1
优点:实现简单,效率高,但目前主流虚拟机均未采用此方法;
缺点:无法解决循环引用的问题;
可达性技术法
通过一系列称为“GC root”的对象作为节点,从这些节点出发,节点走多的路径称为引用链,当一个对象到GC roots 没有任何引用链时,证明对象不可用;
可以作为GC roots 的对象包括下面几种:
- 虚拟机栈中引用的对象
- 本地方法栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
引用
强引用
一般我们new 出来的对象都是强引用;
弱引用
在内存不足时会回收;
软引用
垃圾收集器扫描到就回回收;
虚引用
仅用来标记对象被垃圾回收的活动;
不可达对象并非“非死不可”
不可达对象会先被标记,放入一个队列中,当第二次标记前还没有与CRoot 建立联系,就会被回收掉;
如何判断一个常量是废弃常量?
无引用
如何判断一个类是无用的类?
方法区主要回收的就是无用的类。
无用类需要满足3个条件:
- 1)该类的所有实例都被回收
- 2)加载该类的
ClassLoader
已经被回收 - 3)该类的
java.lang.Class
对象没有在任何地方被引用,无法通过反射访问该类;
4.垃圾回收算法
标记-清除
首先标记不需要回收的对象
,标记完后清除要回收的对象;
缺点:
- 效率问题
- 空间问题(会产生大量不连续的碎片)
标记复制
将内存分为大小相等的两块,当1块用完后,将可用对象复制到另一块,一次性回收;
标记-整理
标记不可回收对象
,将不可用回收对象
统一移动到一端,然后直接清理掉边界以外的内存;
分代收集
将堆内存的对象分为新生代和老年代,根据不同端的特点选用不同的回收算法;
新生代:因每次新生代都会有大量对象死去,可以采用复制算法;仅需要少量的复制,就能完成垃圾收集;
老年代:存活几率高,采用标记-清楚,或者标记整理算法处理;
5.垃圾回收器
Serial收集器
单线程垃圾回收,用户线程和回收线程切换停顿时间太长(在进行垃圾回收的时候,用户线程必须⏸暂停);
新生代采用标记-复制
算法,老年代代用标记-整理
算法
ParNew收集器
Serial收集器
的升级版本,
新生代采用 标记-复制算法;老年代采用 标记-整理算法;
Parallel Scavenge 收集器
更关注吞吐量,提供很多参数,供选择帮用户找到最大吞吐量; 也可以采用自适应策略,将内存优化交给虚拟机处理;
java8 默认的垃圾回收器: Parallel Scavenge + Parallel Old;
Parallel Old 收集器
Parallel Scavenge 收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及 CPU 资源的场合,都可以优先考虑 Parallel Scavenge 收集器和 Parallel Old 收集器;
CMS收集器
- 收集器是一种以获取最短回收停顿时间为目标的收集器;
- HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作;
- 优点:并发收集、低停顿;
- 缺点:对CPU资源敏感; 使用标记-清除 会产生大量的内存碎片;
G1收集器
相对于CMS改进是,停顿时间可以预测;
- 采用标记-清楚算法,会产生内存碎片