首页 > 代码库 > JVM(二)——GC
JVM(二)——GC
引用类型
强引用:类似Object o=new Object()这种引用。只要强引用还存在,对象不会被回收。
软引用:对于软引用关联的对象,在系统将要发生内存溢出前,会被纳入回收范围,并进行第二次回收。
弱引用:被弱引用关联的对象只能生存到下一次回收之前。无论内存是否足够都会被回收。
虚引用:不会影响对象生存时间,也无法获得对象实例,对其唯一期望是关联的实例在被回收时收到一个系统通知。
对象回收
引用计数法(Reference Counting)
给对象中添加一个引用计数器,被引用时+1,失效时-1。任何时刻引用计数为0则对象不可再使用。 这种算法很难应对循环引用的情况。
根搜索算法(GC Roots Tracing)
当一个对象到GC Roots不可达时,证明此对象是不可用的。根搜索算法中,无法到达的对象并非立即回收,而是被标记一次后进行筛选,筛选的条件是此对象是否有必要执行finaliz()方法。存在该方法(未被调用 过)的对象,将被放置在名为F-Queue的队列,并在稍后有虚拟机建立一个低优先级的Finalizer线程执行(虚拟机不承诺该方法执行结束,不一定 会执行), 稍后GC将对F-Queue进行第二次小规模标记,如果此时发现对象可达,将被移出即将回收集合。
可作为GC根的对象包括
虚拟机栈(中局部变量表)中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法中JNI(java本地方法)的引用对象。
方法区回收
废弃常量:与堆中实例回收类似(常量池中类、接口、方法、字段的符号引用也类似)。
无用的类:堆中没有该类实例——加载该类的Classloader已被回收,该类对应的java.lang.Class对象没有引用,无法通过反射访问。
大量使用反射、动态代理、CGLib等bytecode框架的场景,以及动态生成jsp或者osgi这类频繁自定义Classloader的场景都需要该功能
垃圾回收算法
标记-清除算法(Mark-Sweep)
算法:首先标记所有需要回收的对象,在标记完成后,统一回收所有被标记对象。
优点:不存在循环引用问题。
缺点:效率不高,会产生大量不连续内存碎片。
复制算法(Copying)
算法:将可用内存分为两块,每次只使用一块,回收时将此块内存中还生存的对象复制到另一块,把已使用的内存清理掉。
优点:不会出现碎片问题。
缺点:浪费。对象存活率较高时,效率降低。
标记-整理算法(Mark-Compact)
算法:与标记-清除算法类似,只是不直接回清除,而是让所有对象向一端移动,然后清理掉端边界以外的内存。
分代收集算法(Genrerational Collection)
算法:根据对象存活周期划分内存为几块,一般是把堆分为新生代和老年代,根据各个时代不同,采用不同算法。
垃圾收集器
示意图
Serial
单线程垃圾收集器,运行时停止其他线程直到GC结束。
新生代:复制算法。
老年代:标记-整理算法。
ParNew
Serial的多线程版本。
新生代:复制算法。并行。
老年代:标记-整理算法。串行。
Parallel Scavenge
新生代收集器,使用复制算法。并行。类似ParNew收集器,此收集器更关注系统的吞吐量。可以通过参数来打开自适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例。
Serial Old
老年代收集器,使用标记-整理算法。串行。
Parallel Old
Parallel Scavenge的老年代版本。使用标记-整理算法。并行。
Cms
以获取最短回收停顿时间为目标的收集器。标记-清除算法。
步骤:
初始标记:快速标记GC根能连接的对象。
并发标记:根搜索,标记待回收。
重新标记:应对标记期间变动的对象的标记记录。
并发清除:回收。
CPU敏感。
无法处理浮动垃圾:一些在本次GC过程中生成的数据,只能留待下一次GC。如果GC过程中预留内存无法满足,会抛出Concurrent Mode Failure后,启动Serial Old进行老年代垃圾收集。
标记-清除算法会产生大量空间碎片,在无法为对象找到足够的连续空间时,会触发Full GC。
G1
基于标记-整理算法实现,可以精确控制停顿。
内存分配与回收策略
优先在eden分配。大对象直接进入老年代。长期存活对象将进入老年代。
本文出自 “JAVA技术栈笔记” 博客,请务必保留此出处http://stroll.blog.51cto.com/11038467/1852297
JVM(二)——GC