您的位置:首页 > 其它

JVM系列-垃圾收集器与内存分配策略(二)

2017-05-17 17:21 281 查看
摘要: 垃圾收集器与内存分配策略

1,判断对象是否存活

a,引用计数算法 :给对象添加一个引用计数器,每当有个地方引用他时,计数器+1,失效时-1,为0的对象就是不可能再被使用的。java没有选用引用计数算法来管理内存,其中主要原因是很难解决对象之间的互相循环引用的问题。

b,根搜索算法:通过一系列的名为“GC ROOTS”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为应用链,当一个对象到GC ROOTS没有任何引用链相连时,则证明此对象是不可用的。java使用此算法。

c,引用

轻引用:Object object = new Object();这类应用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。

软引用:SoftReference,对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之用并进行第二次回收。

弱引用:WeakReference,只能生存到下次垃圾收集之前。

虚引用:PhantomReference,完全不会对引用的对象生存时间构成影响,也无法通过虚引用来取得一个对象实例。唯一的目的是希望能在这个对象被收集器回收时受到一个系统通知。

d,生存还是死亡

根搜索算法只是对象不可达,也并非非死不可,要经过两次标记,还要进行一次筛选,条件是此对象是否有必要执行finalize()方法。

f,回收方法区

永久代的垃圾收集主要回收废弃常量和无用的类。

2,垃圾收集算法

a,标记-清除算法:效率低,空间碎片不连续。

b,复制算法:就是使用这种算法来回收新生代的。

c,标记-整理算法:老年代收集算法。仍然与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都想一端移动,然后直接清理掉端边界意外的内存。

d,分代收集算法:新生代中每次垃圾收集时都发现有大批对象死去,只有少量存活,选用复制算法,只需要复出少量存活对象的复制成本就可以完成收集。而年老代中因为对象存活率高,没有额外空间对它进行分配担保,必须使用标记-清理或标记整理算法来进行回收。

3,内存分配与回收策略

a,对象优先在Eden分配

b,大对象直接进入老年代

c,长期存活的对象将进入老年代

d,动态对象年龄判定

e,空间分配担保

4,分代回收机制

Sun的 JVM Generational Collecting(垃圾回收)原理是这样的:把对象分为年青代(Young)、年老代(Tenured)、持久代(Perm),对不同生命周期的对象 使用不同的算法。(基于对对象生命周期分析)





如上图所示,为Java堆中的各代分布。

1. Young(年轻代)

年 轻代分三个区。一个Eden 区,两个Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制 过来的并且此时还存活的对象,将被复制年老区(Tenured。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从 Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空
的。

2. Tenured(年老代)

年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。

3. Perm(持久代)

用 于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些 class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过 -XX:MaxPermSize=进行设置。

举 个例子:当在程序中生成对象时,正常对象会在年轻代中分配空间,如果是过大的对象也可能会 直接在年老代生成(据观测在运行某程序时候每次会生成一个十兆的空间用收发消息,这部分内存就会直接在年老代分配)。年轻代在空间被分配完的时候就会发起 内存回收,大部分内存会被回收,一部分幸存的内存会被拷贝至Survivor的from区,经过多次回收以后如果from区内存也分配完毕,就会也发生内 存回收然后将剩余的对象拷贝至to区。等到to区也满的时候,就会再次发生内存回收然后把幸存的对象拷贝至年老区。

通常我们说的JVM内 存回收总是在指堆内存回收,确实只有堆中的内容是动态申请分配的,所以以上对象的年轻代和年老代都是指的JVM的Heap空间,而持久代则是之前提到的 Method Area,不属于Heap。

了解完这些之后,以下的转载一热衷于钻研技术的哥们Richen Wang关于内存管理的一些建议——

1、手动将生成的无用对象,中间对象置为null,加快内存回收。

2、对象池技术 如果生成的对象是可重用的对象,只是其中的属性不同时,可以考虑采用对象池来较少对象的生成。如果有空闲的对象就从对象池中取出使用,没有再生成新的对 象,大大提高了对象的复用率。

3、JVM调优 通过配置JVM的参数来提高垃圾回收的速度,如果在没有出现内存泄露且上面两种办法都不能保证内存的回收时,可以考虑采用JVM调优的方式来解决,不过一 定要经过实体机的长期测试,因为不同的参数可能引起不同的效果。如-Xnoclassgc参数等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: