《深入理解Java虚拟机》笔记4

时间:2022-12-28 10:18:09

垃圾回收器是垃圾回收算法的实现,Java虚拟机的设计者为了

获取最大的性价比,也在不断改进中。硬件在不断变化,多核

的普及,基于单核的收集器应该已经没有太大意义了。Java7中

又新增了g1收集器,没具体研究,【不明觉厉】啊。

暂时觉得垃圾器的细节不用深入研究,性能问题卡到垃圾收集,应该

考虑的是编写的程序质量而不是垃圾回收的性能。

下面介绍垃圾回收的一些原则:

(1) 对象先在eden上分配。

如果eden上剩余空间无法容纳新建立的

对象,则发起一次新生代的垃圾回收。过程是把eden和survivor from

上存活的对象放入survivor to上,之后清理eden和survivor区域。当然,

原来的survivor from变成了survivor to区域,而survivor to变成了

survivor  from区域。

(2)大对象直接进入老生代。

如果有些大对象一直在新生代中用复制

算法拷贝来拷贝去,也是很大的性能浪费,索性不如直接扔到老生代

侯着。(老生代没有新生代垃圾回收的那么频繁,当然老生代收集一次

的花销要远远大于新生代)

虚拟机提供了参数,可以控制大对象的阀值。这样只要大于所配置

的阀值,自动把对象分配到老生代上。

个人认为大对象者,因为需要连续空间应该只要发生在大数组情况下。

ArrayList的底层实现也是数组,这个需要注意。当然也不排除有人把

一个类中写了n多属性,光引用或者基本类型就构成一个大对象,这个

应该很少见。

书上没写虚拟机默认的大对象阀值是多少,亦或如果不手动加入这个

限制,虚拟机是不设上限的?

(3)长期存活对象进入老生代。

有些对象一直存活不能被回收,但是新生代每次垃圾回收都能容纳这种

对象,这样会造成复制的性能浪费。所以,虚拟机给每个对象设了对象

年龄这么个属性,好像这个值是存在对象头中的。对象新生成时,年龄

设为一,之后在每次新生代的收集中如果能躲过一劫,则年龄加一。

虚拟机的默认阀值是15,当一个对象的年龄大于15,将被请如

老生代名人堂。这个阀值可以设置。

(4)动态对象年龄判定   虚拟机有一个策略,如果survivor

中相同年龄的所有对象的大小的总和大于survivor空间的一半,

年龄大于或者等于该年龄的对象就可以直接进入老年代,无须

等到maxtenuringthreshold中要求的年龄。

策略明白,但是好处是什么?作者没举例,我自己想了几个

例子,不一会又被自己推翻了,姑且相信实现虚拟机垃圾回收的

高手。因为是高手啊!

(5)空间分配担保

在发生新生代minor   gc时,虚拟机会检测之前每次晋升到老

生代的平均大小是否大于老生代的剩余空间大小。如果大于,

则改为直接进行一次老生代full   gc。如果小于,则查看担保设置

是否允许失败,如不允许则会伴随一次full   gc。

为避免full  gc过于频繁,担保失败开关一般是打开的。

取平均值比较是动态概率的手段,并不能保证担保不失败。

担保失败后,仍然需要进行一次   full   gc。

作者说担保失败后在full  gc绕的圈子是最大的,但是我

不甚明白,同样是进行一次full  gc,时机的不同会造成

效率的不同?这个问题有机会再查。

 

后面这两点作者只是给出了,这种情况出现的例子,但是

没有说出这样做的好处,感觉有点应付(^_^)