垃圾收集器与内存分配策略

垃圾收集器与内存分配策略

针对对象:Java堆,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间时才能知道会创建哪些对象,这部分内存的分配和回收都是动态的

1.引用计数

应用案例:微软的COM(Component Object Model)技术、使用ActionScript3的FlashPlayer、Python语言以及在游戏脚本领域中被广泛应用的Squirrel;

java没有选用:很难解决对象之间的相互循环引用;

2.根搜索算法

Java,C#,Lisp使用

GC Roots->Reference Chain(从GC Roots到这个对象不可达)

Java里,可作为GC Roots的对象包括下面几种:

□ 虚拟机栈(栈帧中的本地变量表)中的引用的对象。

□ 方法区中的类静态属性引用的对象。

□ 方法区中的常量引用的对象。

□ 本地方法栈中JNI(即一般说的Native方法)的引用的对象。

3.再谈引用

JDK 1.2之后,将引用分为强引用(Strong Reference)、软引用(SoftReference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,这四种引用强度依次逐渐减弱。

□ 强引用就是指在程序代码之中普遍存在的,类似“Object obj = new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

□ 软引用用来描述一些还有用,但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中并进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常。在JDK 1.2之后,提供了SoftReference类。

□ 弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2之后,提供了WeakReference类

□ 虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2之后,提供了PhantomReference类。

4.生存还是死亡

在根搜索算法中不可达的对象,也并非是“非死不可”的;要真正宣告一个对象死亡,至少要经历两次标记过程.
1)进行根搜索后没有引用链,会第一次标记并进行一次筛选;

筛选:是否有必要执行finalize()方法;

当对象没有覆盖finalize,或者该方法已经被虚拟机调用过,则视为没有必要执行;

对于有必要执行finalize()方法,那么这个对象将会被放置在一个名为F-Queue的队列之中,并在稍后由一条由虚拟机自动建立的、低优先级的Finalizer线程去执行(虚拟机会触发但不会等待运行结束,以防造成f-queue中其他对象永久等待);

2)稍后GC将对F-Queue中的对象进行第二次小规模的标记;

如果对象在finalize()中重新与引用链上的任何一个对象建立关联,譬如把自己(this关键字)赋值给某个类变量或对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;

代码清单3-2写法,但这种回收不建议使用;

5.回收方法区

方法区(hospot的永久代):回收的性价比低,回收内容有两部分:

1)废弃常量:没有其他地方引用这个字面量则清除,类似的有常量池中的其他类,接口,方法,字段的符号引用

2)无用的类:回收需满足以下三点

□ 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。

□ 加载该类的ClassLoader已经被回收。

□ 该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

最终是否回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class及-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类的加载和卸载信息。

3)场景:在大量使用反射、动态代理、CGLib等bytecode框架的场景,以及动态生成JSP和OSGi这类频繁自定义ClassLoader的场景

垃圾收集算法
1 标记-清除算法

先标记,后统一收回;缺点:效率不高;2造成空间不连续

2 复制算法

先将内存分成大小相等的两块,使用完一块,将活着的对象复制到另一块,清理调第一块;

解决了效率问题,但内存缩小代价太高;

商业虚拟机使用此法回收新生代,hotspot虚拟机默认eden和survivor比例为8:1,每次使用一块eden和一块survivor,回收时将两块中的存活对象拷贝到另一块survivor,不够用时会依赖其他内存(老年代)分配担保;

3 标记-整理算法

针对老年代,标记可回收对象之后,让所有存活对象向一端移动,然后清理边界以外的

4 分代收集算法

当前都采用这个;根据对象存活周期分为新生代,老年代;新生代采用2中,老年代采用3的算法;

垃圾收集器(hotspot 1.6版)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ICybHlNN-1578644795746)(C:\Users\zhangli\Desktop\1576744582(1)].png)

两个收集器之间存在连线,就说明它们可以搭配使用

1 Serial收集器

单线程,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程

依然是虚拟机运行在Client模式下的默认新生代收集器

2 ParNew收集器

多线程,包括Serial收集器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop TheWorld、对象分配规则、回收策略等都与Serial收集器完全一样

使用 -XX:+UseConcMarkSweepGC选项后的默认新生代收集器,也可以使用 -XX:+UseParNewGC选项来强制指定它,-XX:ParallelGCThreads参数来限制垃圾收集的线程数

是许多运行在Server模式下的虚拟机中首选的新生代收集器,只有它能与CMS收集器(真正意义上的并发)配合工作,在JDK 1.5中使用CMS来收集老年代的时候,新生代只能选择ParNew或Serial收集器中的一个(不能与Parallel Scavenge配合工作)

并行:多条垃圾收集线程并行工作;并发:用户线程和垃圾收集同时执行(多cpu);

3 Parallel Scavenge收集器

新生代,复制算法,并行得多线程收集;

目标:达到可控制的吞吐量,Throughput=运行用户代码时间 /(运行用户代码时间+ 垃圾收集时间)

控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数及直接设置吞吐量大小的-XX:GCTimeRatio参数

4 Serial Old收集器

client模式,在Server模式下,它主要还有两大用途:一个是在JDK 1.5及之前的版本中与Parallel Scavenge收集器搭配使用[插图],另外一个就是作为CMS收集器的后备预案

5 Parallel Old收集器

如果新生代选择了Parallel Scavenge收集器,老年代除了SerialOld(PS MarkSweep)收集器外别无选择;

在注重吞吐量及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器

6 CMS收集器

以获取最短回收停顿时间为目标

整个过程分四步:

□ 初始标记(CMS initial mark):标记一下GC Roots能直接关联到的对象

□ 并发标记(CMS concurrent mark):进行GC RootsTracing,时间久

□ 重新标记(CMS remark):修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记

□ 并发清除(CMS concurrent sweep)

三个缺点:

□ CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量会降低。CMS默认启动的回收线程数是(CPU数量+3)/ 4;虚拟机提供了一种称为“增量式并发收集器”( i-CMS)的CMS收集器变种,跟用户线程抢占cpu资源;

□CMS收集器无法处理浮动垃圾(只垃圾清理得同时程序新产生得垃圾),可能出现“Concurrent ModeFailure(cmf)”失败而导致另一次Full GC的产生;所以再清理阶段也要预留空间给程序运行,一般默认老年底占68%;如果老年代增长不快,可调高参数-XX:CMSInitiatingOccupancyFraction(但可能引起cmf)

□ “标记-清除”带来空间碎片,没有大空间时出发full GC;使用-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费附送一个碎片整理过程(碎片没了停顿久了);-XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的

7 G1收集器(技术发展的最前沿成果)

与CMS得改进

一是“标记-整理”算法实现;二是它可以非常精确地控制停顿,既能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了;

不牺牲吞吐量的前提下完成低停顿的内存回收;避免得全区域收集,堆java堆划分多个大小固定得独立区域,并维护一个优先级;

8 垃圾收集器参数总结
内存分配与回收策略

内存分配细节取决于当前使用的是哪一种垃圾收集器组合,还有虚拟机中与内存相关的参数的设置

本节中的代码在测试时使用Client模式虚拟机运行,没有手工指定收集器组合,换句话说,验证的是使用Serial / Serial Old收集器下

1 对象优先在Eden分配
2 大对象直接进入老年代
3 长期存活的对象将进入老年代
4 动态对象年龄判定
5 空间分配担保
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值