《深入理解Java虚拟机》第3章 GC与内存分配策略

GC的历史远远比Java久远。
哪些需要回收?
何时回收?
怎么回收?
GC会成为系统达到更高并发量的瓶颈,所以需要对这些“自动化”的技术实施必要的调节。

程序计数器以及两个栈,三个区域随线程而生,而灭。方法结束或线程结束,内存自然就回收了。Java堆和方法区不一样,一个接口的多个实现类需要的内存可能不一样,一个方法的多个分支需要的内存也可能不一样。内存的分配和回收都是运行期间,动态的。

3.2.1 引用技术算法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值加1,引用失效时,计数器值减1,计数器为0的对象不能使用。
但:Java语言没有选用此算法管理内存。原因:很难解决对象之间的相互循环引用的问题。

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

可作为GC Roots对象包括下面几种:

  1. VM栈中引用(栈帧的本地变量表)的对象
  2. 方法区中的类静态属性引用的对象
  3. 方法区中的常量引用的对象
  4. 本地方法栈中的Native方法引用的对象

    3.2.3 强引用、软引用、弱引用、虚引用
    强:O o=new O();只要强引用还在,GC永远不会回收被引用的对象
    软:描述还有用,但非必需的对象。
    弱:和上述类似,但更弱。被弱引用引用的对象,只能活到下一次GC发生前。
    虚:无法通过虚引用获得实例。为对象设置虚引用,目的是希望在对象被收集器回收时,收到系统通知

3.2.4 宣告对象真正死亡,至少经过两次标记过程。发现没有与GC Roots链接的引用链,第一次mark并进行一次筛选
筛选的条件是此对象是否有必要执行finalize()方法。当对象覆盖finalize方法,或者finalize已经被VM调用过,这两种情况都是没必要执行。

如果对象被判定为有必要执行finalize,那么这个对象会被放置在一个名为F-Queue的队列之中。并且稍后有一条VM自动建立的,低优先级的Finalizer线程去执行。(只触发,不保证运行结束)稍后GC将对F-Queue中的对象进行二次标记。如果对象要拯救自己,与引用链上的任何一个对象建立关联即可。譬如把自己this复制给某个类变量或对象的成员变量。

任何一个对象的finalize方法只会被系统自动调用一次

3.2.5 回收方法区
hotSpot VM的永久代(方法区)的GC内容:废弃常量、无用的类
无用的类:
1. 该类所有的实例已被回收
2. 加载该类的CLassLoader已被回收
3. 该类对应的java.lang.Class对象没有在任何地方被引用,无法通过反射访问该类的方法。该类所有的实例已被回收

3.3.1 标记-清除算法
缺点:效率问题,空间问题(产生大量不连续的内存碎片,程序以后运行分配较大对象无法找到足够的连续内存)

3.3.2 复制算法
现在的商业VM都用这种方式回收新生代
每次都用其中一块,一块内存用完了,将其中存活的复制到另一块上,已使用的内存一次清空,保留待用。
将内存分为较大的一块eden和较小的两块survivor
当回收时,将eden和survivor中存活的复制到另一块survivor上。
默认eden和survivor的比例是8:1

3.3.3 标记-整理算法(老年代)
应对所有对象都存活的极端情况。
让所有存活的对象向一段移动,然后直接清理端边界以外的内存。

CMS、Serial Old、Parallel Old老年代收集器,新生代ParNew或Serial里二选一
并发:用户线程和垃圾收集线程一起执行
并行:多条垃圾收集线程一起工作,用户线程等待状态。
Parallel Scavenge收集器:控制吞吐量=运行用户代码时间/CPU消耗总时间

3.4.6
CMS:获取最短回收停顿时间为目标(标记清除)
标记清除
初始标记、并发标记、重新标记、并发清除四步

G1:基于标记-整理实现的收集器 。优点:不会产生空间碎片,可以精确地控制,在一个M毫秒时间片段中,GC时间不超过N毫秒。
G1将整个堆划分为多个大小固定的独立区域,并跟踪这些区域里的垃圾堆积程度,优先回收垃圾最多的区域。

3.5 内存分配与回收策略
对象年龄计数器,如果对象在Eden初生并经过第一次Minor GC 后仍存活,且能被Survivor容纳,被移到Survivor,对象年龄设为1.对象每熬过一次Minor GC,年龄就增加一岁。年龄到15岁时,晋升到老年代。

如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于等于该年龄的对象直接进入老年代。无须等到MaxTenuringThreshold要求的年龄。

3.5.5空间分配担保
每次Minor GC时,VM会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间,如果大于,直接进行一次Full GC,如果小于,查看是否允许担保失败,允许,进行Minor GC,不允许,进行一次Full GC。

要坚持写博客,把读书笔记写下去。

    原文作者:java虚拟机
    原文地址: https://blog.csdn.net/qq_24572475/article/details/81781593
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞