狸猫的面试——JVM内存回收

来源:互联网 发布:眼睛肌肉萎缩 知乎 编辑:程序博客网 时间:2024/04/28 21:30

写在前面:详述JVM中内存管理机制以及GC机制

内存组成:

1)堆

所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由From Space和To Space组成


2)栈

每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果

3)本地方法栈

用于支持native方法的执行,存储了每个native方法调用的状态

4)方法区

存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。JVM用持久代(Permanet Generation)来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值

垃圾回收机制

”弱代假说“:

1.绝大多数对象在短时间内变得不可达

2.只有少量年老对象引用年轻对象

老年代引用年轻代:

老年代对于年轻代的引用信息,记录在一个“卡表”中,它由“写闸”管理

回收过程Ed

1)年轻代

对象在Eden区被创建,当Eden区存满时,将存活下来的对象copy到survivor区。然后在survivor两个内存区:From Space和To Space中多次Copy。最后将存活下来的对象copy到老年区。

为了加快内存的分配,在Eden区有两种内存分配算法:

指针碰撞(bump-the-pointer)

指针跟踪分配给Eden区上最新的对象。该对象将位于Eden区的顶部,如果有一份对象被创建,只需要检查Eden区是否有足够大的空间存放该对象。如果空间够用,则将该对象置于Eden区的顶部。然而,如果考虑多线程的环境,则是另外一种情况。为了实现多线程环境下,那么必须加,因此性能会下降。

线程本地分配缓冲(TLAB)

为了解决上述问题,允许每个线程在Eden区有自己的一小块私有空间,因为每个线程只能访问自己的TLAB,所以在这个区域甚至可以使用无锁的指针碰撞技术进行内存分配。

2)老年代

GC时刻:老年代存满时

JDK7中有5种垃圾收集器

1.serial收集器——在整个扫描和复制过程采用单线程的方式来进行,适用于单CPU、新生代空间较小及对暂停时间要求不是非常高的应用上,是client级别默认的GC方式,可以通过-XX:+UseSerialGC来强制指定

2.Parallel收集器——吞吐量优先垃圾收集器,可用-XX:+UseParallelGC来强制指定,用-XX:ParallelGCThreads=4来指定线程数

3.Parellold收集器

4.ConcurrentMark&sweepGC收集器

5.GarbgageFirst收集器

标记——清楚——整理算法(serial)

1.从头开始检查内存空间,并且标记存活的对象

2.从头开始,顺序的填满堆内存空间,将存活的对象连续存放在一起,这样堆分成两部分:一边有存放的对象,一边没有对象。

标记——汇总——压缩算法(parellel)

汇总步骤与清理的不同之处在于,其将依然幸存的对象Copy到GC预先处理好的不同区域。

0 0