《深入理解java虚拟机》第三章

本章解决一下三个问题!!!

1.哪些内存需要回收(安全点 四种引用 )

2.什么时候需要回收

3.如何回收?(垃圾收集算法 垃圾收集器)

一.那些内存需要回收?

答;死去的内存需要回收,那么问题来了如何判断哪些内存死去了?
引用计数法 已经过时,主流虚拟机不再使用,目前使用可达性分析算法

1.引用计数法

引用计数法实现:对象添加一个引用计数器,每当有一个地方有引用,那么计数器加1,;每当引用失效,计数器数值减1;当计数器数值为0,代表可以回收。
引用计数法为何不被主流虚拟机使用:如下图中代码所示,对象A引用这对象B,对象B引用着对象A,然后A与B分别用null(这样想把A与B的引用计数变成0),这时候A与B已经无法再被访问,但是由于相互引用,计数器值不是0,所以按照这种方法无法被gc回收掉。
《深入理解java虚拟机》第三章_第1张图片

2.可达性分析算法(GC Roots 可以访问到的)

java堆的内存回收
实现 :从“GC Roots” 起始点开始,从这些根结点向下访问,只要可以访问到,就是‘活’的对象,访问不到就是需要回收的‘死’对象。
GC Roots:1.虚拟机栈中引用的对象 2. 本地方法栈中Native方法引用的对象
这里涉及到一个枚举根结点的问题:枚举根结点,必须stop the world 也就是说不能再枚举的时候,对象引用关系还在不停地变化
安全点:目前主流的虚拟机再枚举根结点的时候,会去一个地方找存这些对象引用的地方,存对象引用的就是OopMap数据结构;同事能够引起对象引用发生变化的指令有很多,由于内存空间的制约,无法为每条指令都生成OopMap结构去存这些对象引用发生的变化,因此虚拟机再特定的位置生成OopMap,这些位置就是安全点。
安全域 安全点的概念是针对运行的线程,去跑到安全点位置,然后响应GC事件,而一些线程可能Sleep或者Blocked状态无法运行,故有了安全域,只要进入安全域这个代码片段,就都是安全的,可以响应GC,引用关系不会发生变化。
3。方法区中常量引用的对象 4。方法区中类静态属性引用的对象
四种引用:强引用,软引用,弱引用,虚引用
《深入理解java虚拟机》第三章_第2张图片

3.方法区的内存回收(回收废弃常量和无用的类)

3.1 废弃常量

举例:当“abc”已经进入了常量池,但是系统中没有任何一个地方引用“abc”这个常量,那这个“abc”就是废弃常量

3.2 无用的类

《深入理解java虚拟机》第三章_第3张图片

三.如何回收

1.垃圾收集算法

1.1标记-清除算法

算法实现:标记:采用可达性分析算法进行标记
清除:将标记出来的需要回收的算法进行回收
缺点:1.效率问题 2.空间问题 会产生大量不连续的内存碎片,可能无法分配大对象

1.2 复制算法

算法实现: 将内存分为两块,每次使用其中一块,当使用的这一块用完了,将存活的对象复制到另一个块,然后将用完的这一块清除掉。
现代商业虚拟机:分为eden survivor1 survivor2 其中eden与survivor1是用来可用内存空间,survivor2是作为垃圾回收的,这基于每次新生代中只有不超过10%的存活对象(8:1:1),当survivor2的区域的内存不够用的时候,需要老年代进行分配担保。

1.3 标记-整理算法

算法实习:标记:可达性分析算法进行标记 整理:将所有存活的对象移动到一端,将端边界以外的所有内存清理掉。

1.4 分代收集算法

算法实现: 年轻代 复制算法 老年代 标记整理 或者 标记清除算法

2.垃圾收集器

2.1 Serial收集器 新生代

特点:新生代单线程收集器,进行垃圾收集时必须暂停其它所有的工作线程,直到收集完成。
适用范围:运行在Client模式下的虚拟机
《深入理解java虚拟机》第三章_第4张图片

2.2 ParNew收集器 新生代

特点:其实就是Serial收集器的多线程版本,有时候由于线程切换的原因还不如Serial收集器
《深入理解java虚拟机》第三章_第5张图片

2.3 Parallel Scavenge 收集器( 新生代 吞吐量优先收集器)

新生代收集器
吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
参数:MaxGCPauseMills 和 GCTimeRatio
MaxGCPauseMills :最大的GC停顿时间,不超过这个值
GCTimeRatio: 大于0小于100的整数 举例 当GCTimeRatio = 99 那么GC时间所占的比重为 1/(1+99) = 1%
《深入理解java虚拟机》第三章_第6张图片

2.4 Serial Old 收集器(老年代)

单线程收集器,老年代,标记-整理算法
适用范围:Client模式下的虚拟机使用
《深入理解java虚拟机》第三章_第7张图片

2.5 Parallel Old收集器(老年代)

之前Parallel Scavenge收集器只有Serial Old搭配,效率低,这个收集器专门域ParNew搭配
《深入理解java虚拟机》第三章_第8张图片

2.6 CMS收集器

四个步骤:1.初始标记 2。并发标记 3。冲洗标记 4。并发清除

1.初始标记

只用来标记GC Roots能直接关联到的对象,速度很快

2.并发标记

标记在初始标记完后的对象,这些对象在引用链上可以访问到的对象。这个过程是与用户线程一起运行的。

3.重新标记

重新标记是为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录。

4.并发清除

这个阶段是清除掉与上面阶段标记后,清除掉不再被引用的内存。与用户的线程并发运行。

5.CMS缺点

1.无法处理浮动垃圾 浮动垃圾就是在并发清除的时候用户线程运行产生新的垃圾
2.并发清除阶段采用的”标记-清除”算法,会空间碎片过多,无法存储大对象。
3.并发的原因 CMS会对CPU特别的敏感。

2.7 G1收集器

1.为何叫G1收集器

G1将各个堆划分成对个Region,G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的的空间大小以及回收所需的经验值),在后台维护一个优先队列,每次根据允许的收集时间,优先回收价值最大的Region#

2.相对于CMS收集器有何优势

优势1.总体上是‘标记-整理’算法 2.可预测的停顿

3.G1收集器的运作过程

1.初始标记 2.并发标记3.最终标记 这三步与CMS基本相同
4.筛选回收 首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来来制定回收计划。


内存分配与回收策略

1.对象优先在Eden分配
2.大对象直接在老年代分配 -XX:PretenureSizeThreshold参数,当大于这个参数的对象直接分配到老年大
3.长期存活的对象分配到老年代 -XX:MaxTenuringThreshold 代数 当熬过的GC次数达到此参数 那么将此对象分配到老年代
4.空间分配担保 复制算法中如果Survivor中空间不足以容纳eden中活着的对象,那么把这些活着的对象直接移动刀老年代中。HandlePromotionFailure 参数 允许担保失败 意思就是检查历代的老年代最大可用连续空间 大于 历代的进入到老年代中的对象的平均大小
大于 则进行 MinorGC 这个只是一个估计值 也有可能出现进入老年代的大小大于老年代的最大可用连续空间 还不得不进行full GC

你可能感兴趣的:(Java)