对于堆内存,虚拟机如何进行分代管理?
分代:JVM根据对象在内存中存活时间的长短,把堆内存分为新生代和老年代
新生代:由Eden区+(S0+S1) Survivor区组成
- 大部分情况下,对象优先分配到Eden区,如果对象实在太大,新生代整个都放不下的话,可直接放在老年代区
- 当Eden区满时,JVM会触发一次Minor GC(回收速度快)
Minor GC
(1)当Eden满了之后,进行Minor GC,将需要保存的数据复制到S0中
(2)当下一次Eden满了之后,进行Minor GC,将原来S0存放的数据复制到S1中,将Eden中需要保存的数据也复制到S1中
(3)长期存活的对象将进入老年代,默认是15岁,也就15次 的Minor GC之后放入老年代,也可以自定义设置
(4)也不是必须达到指定时间才能晋升老年代。如果大于或等于某年龄的对象总和,大于Survivor空间的一半,可直接进入老年代
老年代Full GC
- 主要存放应用程序中生命周期长的内存对象,老年代的对象比较稳定,所以Full GC不会频繁执行,Full GC会清理整个堆空间
- 进行Full GC之前一般会进行一次Minor GC,使得有新生代的对象晋升老年代,导致空间不够用才触发
- 当无法找到足够大的连续空间分配给新创建的较大对象时,也会提前触发一次Full GC进行垃圾回收腾出看空间
- Full GC会导致Stop The World
2、垃圾回收算法有哪些?每个算法各自有何优劣?
- 两种垃圾回收的机制
(1)引用计数器:当对象被引用,程序计数器+1;释放-1;当为0时证明对象未被引用,可回收
很明显这种算法有明显的缺陷,对于循环引用的情况下,对象不会被回收。例如:
(2)可达性分析法:通过一系列称为“GC Roots”的对象作为起点;从此起点向下搜索,所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连接,代表此对象不可达。
Java可以作为GC Roots的对象包括:
- 虚拟机栈(栈帧中的局部变量表)中的引用对象
- 类静态属性引用的对象
- 常量引用的对象
- 本地方法栈中JNI(Native方法)的引用对象
- 三种垃圾回收算法
(1)标记-清理
在GC的时候,先进行扫描,,把需要清理的无用对象进行标记,然后将这些对象直接进行清理/
缺点:产生内存碎片,造成内存浪费。如果清理了两个1KB大小的对象,再添加一个2KB的对象,无法放入到着两个位置。
(2)标记-整理(老年代采用的方式)
在标记-清理的基础上,清理完成后,将内存空间进行整理,使得空间紧凑重新排列,解决了内存碎片的问题
缺点:开销较大
(3)复制(新生代采用的方式)
将空间一分为二,在清理的时候,将需要保存的对象复制到第二块区域上,复制的时候直接紧凑排列,然后把原来的一块区域清空
缺点:浪费空间