jvm(3)-垃圾收集器与内存分配策略
O1)虚拟机栈中引用的对象;O2)方法区中类静态属性引用的对象;O3)方法区中常量引用的对象;O4)本地方法栈中JNI(Native方法)引用的对象;
2.1)强引用:指在程序中普遍存在的,类似 Object obj = new Object();只要强引用存在,就不会被回收;2.2)软引用:用来描述一些还有用但并非必须的对象;在系统将要发生内存溢出异常前,将会把这些对象列进回收范围中进行第二次回收;(SoftReference类来实现软引用)2.3)弱引用:也是用来描述非必须对象的,但它的强度比软引用还要弱,被弱引用关联的对象只能生存到下一次GC之前;(WeakReference类来实现弱引用)2.4)虚引用:它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成威胁,也无法通过一个虚引用获得一个对象实例。为一个对象设置虚引用的目的是: 能够在这个对象被回收时 收到一个系统通知。(PhantomReference 类来提供虚引用)
mark1)如果对象在进行可达性分析后发现没有与 GC roots 相连接的引用链,那他将会被第一次标记并且进行一次筛选;筛选条件是此对象是否有必要执行 finalize方法。如果该对象没有覆盖 finalize方法,或者finalize方法已经被虚拟机调用过,虚拟机将这两种cases 都视为没有必要执行;
mark2)如果这个对象被判定有必要执行 finalize方法,那么这个对象将会放置到一个叫做F-Queue的队列中,并在稍后由一个虚拟机自动建立的,低优先级的finalizer 线程去执行它。
这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束。这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中的其他对象永久处于等待状态,甚至导致整个内存回收系统崩溃。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那它就真的离死不远了。(干货——finalize()方法是对象逃脱死亡命运的最后一次机会)
2.1)源代码/*** 此代码演示了两点: * 1.对象可以在被GC时自我拯救。 * 2.这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次* @author zzm*/ public class FinalizeEscapeGC {public static FinalizeEscapeGC SAVE_HOOK = null;public void isAlive() {System.out.println("yes, i am still alive :)");}@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("finalize mehtod executed!");FinalizeEscapeGC.SAVE_HOOK = this; // System.gc()调用到了这里,拯救成功}public static void main(String[] args) throws Throwable {SAVE_HOOK = new FinalizeEscapeGC();//对象第一次成功拯救自己SAVE_HOOK = null;System.gc();// 因为Finalizer方法优先级很低,暂停0.5秒,以等待它Thread.sleep(500);if (SAVE_HOOK != null) {SAVE_HOOK.isAlive();} else {System.out.println("no, i am dead :(");}// 下面这段代码与上面的完全相同,但是这次自救却失败了SAVE_HOOK = null;System.gc();// 因为Finalizer方法优先级很低,暂停0.5秒,以等待它Thread.sleep(500);if (SAVE_HOOK != null) {SAVE_HOOK.isAlive();} else {System.out.println("no, i am dead :(");}} }
2.2)打印结果finalize mehtod executed! yes, i am still alive :) no, i am dead :(
笔者并不鼓励大家使用这种方法来拯救对象。相反,笔者建议大家尽量避免使用它,因为它不是C/C++中的析构函数,而是Java刚诞生时为了使C/C++程序员更容易接受它所做出的一个妥协。它的运行代价高昂,不确定性大,无法保证各个对象的调用顺序。finalize()能做的所有工作,使用try-finally或其他方式都可以做得更好、更及时,大家完全可以忘掉Java语言中还有这个方法的存在。
1)永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。回收废弃常量与回收Java堆中的对象非常类似。以常量池中字面量的回收为例,假如一个字符串“abc”已经进入了常量池中,但是当前系统没有任何一个String对象是叫做“abc”的,换句话说是没有任何String对象引用常量池中的“abc”常量,也没有其他地方引用了这个字面量,如果在这时候发生内存回收,而且必要的话,这个“abc”常量就会被系统“请”出常量池。
C1)该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
C2)加载该类的ClassLoader已经被回收。
C3)该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
3)是否对类进行回收: HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class及-XX:+TraceClassLoading、 -XX:+TraceClassUnLoading查看类的加载和卸载信息。
为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。(现在的商业虚拟机都采用这种收集算法来回收新生代)
现在的商业虚拟机都采用这种收集算法来回收新生代,IBM的专门研究表明:新生代中的对象98%是朝生夕死的,所以并不需要按照1∶1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地拷贝到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor的空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8∶1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的内存是会被“浪费”的。(干货——注意这里的Eden 和 Survivor空间,后面的内容会用到)
当前商业虚拟机的垃圾收集都采用“分代收集”(Generational Collection)算法,这种算法并没有什么新的思想,只是根据对象的存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。
- 1)Serial收集器(单线程收集器)
- 2)ParNew收集器(Serial收集器的多线程版本)
- 3)Parallel Scavenge收集器: Parallel Scavenge收集器的目标: 则是达到一个可控制的吞吐量(Throughput)。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间),虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。(干货——吞吐量的定义)
- 4)Serial Old收集器(是Serial收集器的老年代版本)
- 5)Parallel Old收集器(Parallel Scavenge收集器的老年代版本)
- 6)CMS收集器(Concurrent Mark Sweep):目的是获取最短回收停顿时间,并发收集,低停顿;
- 7)G1收集器(Garbage-First):可建立可预测的停顿时间模型,且面向server 的 应用;
【3】理解GC日志
1)阅读GC日志是处理jvm 内存问题的基础技能
2)看个荔枝:
对以上日志的分析(Analysis):
- A1)33.125:代表GC发生的时间,表示从 jvm 启动以来经过的秒数;
- A2)GC日志开头的 [GC 和 [FullGC 说明了这次垃圾收集的停顿类型: 如果是调用 System.gc() 方法进行收集,将显示 [Full GC(System);
- A3)[DefNew,[Tenured,[Perm 表示: GC发生的区域,这里显示的区域名称与使用的GC收集器密切相关,如 DefNew == Default New Generation;
- A4)后面方括号内部的 3324K->152K(3712K):表示 GC 前该内存区域已经使用容量->GC后该内存区域已使用容量(该内存区域的总容量);
- A5)括号外的 3324K->152K(11904K): 表示GC前java 堆已使用容量->GC后堆已使用容量(java堆总容量);
- A6)0.0031680 secs表示: 该内存区域进行GC 所占用的时间;
- A7)有的收集器会给出具体的GC时间, 如[time: user=0.01 sys=0.00 real=0.02 secs],user, sys, real 分别代表用户态消耗的CPU时间, 内核态消耗的CPU事件 和 操作从开始到结束所经过的墙钟时间。
3)垃圾收集器参数总结
jvm(3)-垃圾收集器与内存分配策略相关推荐
- Java虚拟机(jvm)——垃圾收集器与内存分配策略
文章目录 判断对象的存活 引用和对象死亡 4 种引用 宣告对象死亡 回收方法区 垃圾回收算法 标记清除算法: 标记复制算法: 标记整理算法 分代收集算法: 增量收集算法 一些相关的概念: System ...
- JVM篇·垃圾收集器与内存分配策略
Java堆内存的整理方法 本文为<深入理解Java虚拟机_第三版 周志明>学习笔记 引用计数法 概念:在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,当引用失效时,计数 ...
- jvm垃圾收集器与内存分配策略
2019独角兽企业重金招聘Python工程师标准>>> 垃圾收集器与内存分配策略: 以下参考周志明的<<深入理解jvm高级特性与最佳实践>>. 判断对象是否存 ...
- JVM:垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 1.对象已死吗 1).引用计数算法 引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就 ...
- java eden分配参数,JVM垃圾收集器与内存分配策略,
垃圾收集器与内存分配策略 对象存活判断 引用计数算法 给对象添加一个计数器,每有一个引用+1,当引用失效-1,若为0则不在被使用. 可达性分析算法 对象是否可到达GC roots 或者说GC root ...
- 垃圾收集器与内存分配策略(五)之垃圾日志与常见参数
2019独角兽企业重金招聘Python工程师标准>>> 垃圾收集器与内存分配策略(五)--垃圾日志与常见参数 理解GC日志 每个收集器的日志格式都可以不一样,但各个每个收集器的日志都 ...
- 【深入理解Java虚拟机学习笔记】第三章 垃圾收集器与内存分配策略
最近想好好复习一下java虚拟机,我想通过深读 [理解Java虚拟机 jvm 高级特性与最佳实践] (作者 周志明) 并且通过写一些博客总结来将该书读薄读透,这里文章内容仅仅是个人阅读后简短总结,加强 ...
- java_opts gc回收器_jvm垃圾收集器与内存分配策略
垃圾收集器与内存分配策略: 以下参考周志明的<>. 判断对象是否存活: 引用计数:通过判断对象被引用的次数(为0,则表示不可被使用),但这很难解决对象相互循环引用的问题. 根搜索算法:即采 ...
- 7种垃圾收集器与内存分配策略,看这一篇就够了
垃圾收集器与内存分配策略-垃圾收集器 (A).图中展示了7种不同分代的收集器: Serial.ParNew.Parallel Scavenge.Serial Old.Parallel Old.CMS. ...
最新文章
- Solaris下ftp配置(初稿-待补充)
- 如何求一个数的因数 c语言代码,【代码】求一个数的因数和、求优化、顺便也供新人参考算法...
- golang协程介绍和理解
- 设置DVWA出现Could not connect to the MySQL service. Please check the config的解决方法,默认登录账号
- ip访问次数统计 nginx_Linux分析Nginx日志统计IP访问次数的shell脚本
- java ocr linux_linux系统如何使用tess4j(java)进行ocr图片文字识别
- 野生前端的数据结构练习(11)动态规划算法
- mysql 左右值算法详解_无限分类左右值算法的常规操作逻辑
- hive报错(1)MoveTask
- 如何通过svg代码还原图片_如何通过nginx反向代理来调试代码?
- 车联网中如何应用大数据
- java开发工程师必看书籍
- 使用命令行强制注销远程登录用户
- 未来计算机将朝着微型化成,湖北汽车工业学院大学计算机基础复习题(费劲整理的,带答案,考试命中概率很大)....
- svn拉取文件合并_svn如何使用import目录作为工作拷贝+我的svn学习笔记
- LeetCode——1646. 获取生成数组中的最大值
- 九张图看懂互联网金融模式
- Nelder Mead算法推荐阅读博文
- FP-Growth算法详解
- 一款优秀数据库中间件的不完全解析
热门文章
- CCPC秦皇岛gym102361A. Angle Beats
- H - Tunnel Warfare HDU - 1540
- 2020牛客国庆集训派对day2 VIRUS OUTBREAK
- 1143 Lowest Common Ancestor 甲级
- [ZJOI2010] 排列计数(dp + 组合数)
- [指数型生成函数专练]chocolate,红色病毒问题,排列组合,字串数
- 模板:线段树优化建图
- NOI.AC-保镖【贪心,对顶堆】
- nssl1230-序列【位运算】
- codeforces1437 E. Make It Increasing——最长上升子序列