对象内存分配问题、回收分配给对象内存的问题
没有被其他对象引用
对象实例相互引用,循环引用 主流的gc没用这种方法
离散数学的图论理解 从gc Root 向下搜索走过的路径,成为引用链。 存活标记为可达。 垃圾对象则不可达
不利于后来程序运行时,无法找到较大的连续内存分配
对象存活率低的场景 不会有碎片,每次对每个半区进行回收
商用虚拟机,多采用这种方法回收年轻代基本只有10%存活 年轻代
在标记清除做了改进 解决空间碎片化问题
生命周期划分不同区域。采用不同垃圾回收算法
所有java出生的地方。申请的内存和存放都是在此处 Java对象一般不需要长久存活,朝生夕灭
每次gc年龄递增+1 通过调节年龄到老年代的参数,默认15岁
一般老年代回收,会伴随年轻代。 Full 比 Minor 执行慢10倍左右,但执行频率低
触发回收Full 老年代空间不足。 jdk1.7及以前永久代空间不足 CMS GC 同时。年轻代放不下,老年代也放不下。
jdk8将永久代删掉了 年轻代:存活率低,采用复制算法 老年代:存活率高,采用标记整理、清除
空间分配:老:新大概2:1
什么是安全点?
JVM的快照下分析,其他线程停止等待gc线程。 不能存在gc分析过程中对象引用状态还在不停变换,因此分析结果在某个点具有确定性,这个点叫做安全点。 程序必须到达安全点才会停顿下来。 安全点太多,GC 过于频繁,增大运行时负荷;安全点太少,GC 等待时间太长。
Server 启动慢,重型,运行稳定后变快 Client 启动快,轻型,运行后,没server快
减少gc线程等待时间(系统停顿时间)适合交互 在程序启动时可以设置 指定 收集器 Java最基本历史最悠久的收集器 jdk1.3.1以前是Java虚拟机年轻代的唯一选择
Server模式下的年轻代首选 除了Serial 只有ParNew与CMS配合使用
多线程 关注系统吞吐量,适合后台计算。 如果对收集器调优不熟悉,可以在启动时加上自适应 调节策略,把内存管理和调优任务交给虚拟机执行。
jdk6之后提供 比较尴尬的是 在此之前,如果年轻代选择了Parallel Scavenge,老年代必须选择Serial Old收集器 。由于老年代服务端单线程性能上的拖累。使年轻代Parallel Scavenge未必能达到吞吐量最大化的效果。单线程的老年代无法充分利用年轻代多线程cpu的处理能力。 因此在老年代很大,硬件高级的环境中。甚至没有ParNew和CMS的组合给力。 直到Parallel Old出现,可以与Parallel Scavenge组合吞吐量优先收集器有了名副其实的组合。 适用:吞吐量、cpu敏感的场合
CMS占据着垃圾回收老年代的半壁江山 垃圾回收线程几乎和用户线程同时工作 但是还不能做到完全不需要(系统停顿时间),只是尽可能的缩短了应用时间 适用场景:对停顿比较敏感,需要更大的内存和cpu ,更牛的硬件 JVM中有很多存活时间相对较长的对象,可以用CMS 只扫描根直接关联的节点 缺点:标记清除,碎片化严重
用于替换掉JDK5中的CMS收集器
CMS 和 G1使用了新的独立框架,而其他的共用框架类似
C++析构函数,调用时机确定,对象离开作用域就会被清除掉 Java的finalize(),具有不确定性,当垃圾回收器宣告一个对象死亡时至少经过两次标记过程。 可达性分析之后发现,当没有和GC ROOT相链接的引用链,会被第一次标记。并且判断是否执行finalize方法,如果对象覆盖finalize()方法且未被引用, 这个对象就会被放置在F-Queue队列中,并在稍后由虚拟机自动建立的低优先级finalize线程去执行触发finalize()方法 。(由于优先级比较低,不承诺等待其运行结束,方法执行了随时可能被终止)给对象创造了最后一次重生的机会
不建议使用:由于运行的不确定性较大,无法保证各对象的调用顺序,同时运行代价相当高昂。
代码证明
强 宁可终止也不回收
软 内存不够用再回收 适用:内存缓存 包装使用:SoftReference< String> 配合引用队列使用:
弱 见到就回收 垃圾回收优先级低 适用:偶尔使用 WeakReference< String >
必须和队列联合使用。软引用、弱引用也可以用此种方式 哨兵作用:判断是虚引用是否加入队列中,知道gc是什么时候执行的
依赖节点之间类似链表 链表的容器,其自己仅存储当前的head节点。后面的节点由referent.next()链接 除强引用,其他引用在gc后,将引用对象放在ReferenceQueue
referent新创建对象的引用 queue类似链表结构 next指向下一个引用
开始时queue为空 normal打印载入的名字 weak没有打印 gc垃圾回收 weak载入到了主方法内,此时name被垃圾回收所以输出为null
对ReferenceQueue进行监控,如果有对象被回收,那么响应的Reference对象就会被放到Queue里面,就可以拿Refernce做一些事情。 如果不带Queue,就要不断的轮询Reference,通过不断的判断里面的get方法是否返回null ,来判断是否被回收。 通过Get方法来判断返回对象是否为空并不适用虚引用,因为此get方法返回值一直为null,只能通过Queue来判断
弱引用哨兵功能
主方法
输出