点击上方“方志朋”,选择“设为星标”

回复”666“获取新整理的面试资料

随着编程语言的发展,GC的功能不断增强,性能也不断提高,作为语言背后的无名英雄,GC离我们的工作似乎越来越远。作为Java程序员,对这一点也许会有更深的体会,我们不需要了解太多与GC相关的知识,就能很好的完成工作。那还有必要深入了解GC吗?学习GC的意义在哪儿?

不管性能提高到何种程度,GC都需要花费一定的时间,对于实时性要求较高的场景,就必须尽量压低GC导致的最大暂停时间 (GC会导致应用线程处于暂停状态),举两个例子:

  • 实时对战游戏:如果因为GC导致玩家频繁卡顿,任谁都会想摔手机吧。

  • 金融交易:在某些对价格非常敏感的交易场景下(比如,外汇交易中价格的变动非常频繁),如果因为GC导致没有按照交易者指定的价格进行交易,相信我,这些交易者非生吃了你。

但也有许多场景,GC的最大暂停时间没那么重要,比如,离线分析、视频网站等等。因此,知道这个GC算法有这样的特征,所以它适合这个场景,对程序员来说非常有价值,这就是我们学习GC最重要的意义。接下来,我们将一步步走进GC的世界。

从诞生之初,人们就在思考GC需要完成的3件事情:何为垃圾?何时回收?如何回收?垃圾收集器在对内存进行回收前,第一件事就是要确定这些对象之中哪些还”活着“,哪些已经”死去“,而这些”死去“的对象,也就是我们所说的垃圾。

引用计数法

判断对象是否存活,其中一种方法是给对象添加一个引用计数器,每当有一个地方引用它,计数器的值就加1,当引用失效时,计数器的值减1,任一时刻,如果对象的计数器值为0,那么这个对象就不会再被使用,这种方法被称为引用计数法。在整个回收过程中,引用计数器的值会以极快的速度更新,因而计数值的更新任务变得繁重,而且需要给计数器预留足够大的内存空间,以确保它不会溢出。因此,引用计数法的算法很简单,但在实际运用中要考虑非常多的因素,所以它的实现往往比较复杂,更为重要的是它不能解决对象之间的循环引用问题。

举个栗子,下面的代码片段展示了为什么引用计数法无法解决循环引用的问题。

public class GcDemo {

   public static void main(String[] args) {

       // 在栈中分配内存空间给obj1,然后在堆中创建GcObject对象A

       // 将obj1指向A实例,这时A的引用计数值 = 1

       GcObject obj1 = new GcObject();

       // 同理,GcObject实例B的引用计数值 = 1

       GcObject obj2 = new GcObject();

       // GcObject实例2被引用,所以B引用计数值 = 2

       obj1.instance = obj2;

       // 同理A的引用计数值 = 2

       obj2.instance = obj1;

       // 栈中的obj1不再指向堆中A,这时A的计数值减1,变成1

       obj1 = null;

       // 栈中的obj2不再指向堆中B,这时B的计数值减1,变成1

       obj2 = null;

   }

}

class GcObject {

   public Object instance = null;

}

仔细阅读代码中的注释,并结合下面的内存结构示意图,应该可以很好的理解其中的原因:如果JVM垃圾收集器采用引用计数法,当obj1和obj2不再指向堆中的实例A、B时,虽然A、B已经不可能再被访问,但彼此间相互引用导致计数器的值不为0,最终导致无法回收A和B。

可达性分析

引用计数法有一个致命的问题,即无法释放有循环引用的垃圾,因此,主流的Java虚拟机都没有选用引用计数法来管理内存,而是通过可达性分析 (Reachability Analysis)来判定对象是否存活。可达性分析的基本思路是找到一系列被称为”GC Roots“的对象引用 (Reference) 作为起始节点,通过引用关系向下搜索,能被遍历到的 (可到达的) 对象就被判定为存活,其余对象 (也就是没有被遍历到的) 自然被判定为死亡。这里需要着重理解的是:可达性分析本质是找出活的对象来把其余空间判定为“无用”,而不是找出所有死掉的对象并回收它们占用的空间,简略的示意图如下所示。

从图中可以看出,经过可达性分析后,有不少对象没有在GC Roots的引用链条上,其中还包含一些相互引用的对象,这些对象在不久以后都会被垃圾收集器回收,因此,可达性分析算法可以有效解决引用计数法存在的致命问题。

但是,首次被标记的对象并一定会被回收,它还有自救的机会。一个对象真正的死亡至少需要经历两次标记过程:

标记所有不可达对象,并进行筛选,筛选的标准是该对象覆盖了finalize()方法且finalize()方法没有被虚拟机调用过,选出的对象将被放置在一个“即将被回收”的队列中。稍后虚拟机会创建一个低优先级的Finalizer线程去遍历队列中的所有对象并执行finalize()方法 对队列中的对象进行第二次标记,如果对象在finalize()方法中重新与引用链上的任何一个对象建立关联,那么这个对象将被移除队列,而还留在队列中的对象,就会被回收了。

要正确的实现可达性分析算法,就必须完整地枚举出所有的GC Roots,否则就有可能会漏掉本应存活的对象,如果垃圾收集器错误的回收了这些被漏掉的活对象,将会造成严重的bug。GC Roots作为垃圾回收的起点,必须是一些列活的引用 (Reference) 集合,那这个集合中究竟包含哪些引用?为什么这些引用可以作为GC Roots?要回答好这两个问题,需要对Java对象在内存中布局有一些初步的了解,所以,在下节会对相关知识进行补充。

参考资料

周志明 著; 深入理解Java虚拟机(第2版); 机械工业出版社,

2013 知乎上关于GC ROOTS的问题

CHEN川

https://www.jianshu.com/p/d9840ebdea25

热门内容:     

  • 接私活必备的10个开源项目!

  • 让 Spring Boot 启动更快一点

  • 一次非常有意思的 SQL 优化经历:从 30248.271s 到 0.001s

  • 进程与线程的一个简单解释

  • 这道字节跳动的面试题,据说多数人都不会

  • 中台禁区:为什么最关键的组织架构却鲜少人谈?

  • 职场老鸟的焦虑与出路

  • fastjson又被发现漏洞,这次危害可导致服务瘫痪!

  • 惊呆了,Spring Boot居然这么耗内存!

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ♡

visual studio内存溢出检测工具_详解JVM内存管理与垃圾回收机制2 何为垃圾相关推荐

  1. 详解JVM内存管理与垃圾回收机制2 - 何为垃圾

    随着编程语言的发展,GC的功能不断增强,性能也不断提高,作为语言背后的无名英雄,GC离我们的工作似乎越来越远.作为Java程序员,对这一点也许会有更深的体会,我们不需要了解太多与GC相关的知识,就能很 ...

  2. java 内存溢出时打印_如何在JVM内存溢出的时候自动dump内存快照

    解决OOM问题的一个初步思路 首先第一个问题,假设发生OOM了,必然说明系统中某个区域的对象太多了,塞满了那个区域,而且一定是无法回收掉那些对象,最终才会导致内存溢出的. 既然是这个思路,要解决OOM ...

  3. Visual Studio集成Qt环境搭建_详解与测试

    1.利器≠戾气 接了两个项目,而这两个项目说起来也很有意思. 一个是监护仪软件开发,要求利用MFC进行开发,因为在此之前接近两年时间一直进行MFC开发:来到清华后,碰到了好多的计算机编程大牛,就GUI ...

  4. docker 管理工具_详解Docker可视化管理工具shipyard--部署教程及功能展示

    概述 谈及docker,避免不了需要熟练的记住好多命令及其用法,对于熟悉shell.技术开发人员而言,还是可以接受的,熟练之后,命令行毕竟是很方便的,便于操作及脚本化.但对于命令行过敏.非技术人员,进 ...

  5. 详解JVM内存管理与垃圾回收机制5 - Java中的4种引用类型

    在Java语言中,除了基础数据类型的变量以外,其他的都是引用类型,指向各种不同的对象.在前文我们也已经知道,Java中的引用可以是认为对指针的封装,这个指针中存储的值代表的是另外一块内存的起始地址(对 ...

  6. Win7系统Visual Studio 2013配置OpenCV3.1图文详解

    Win7系统Visual Studio 2013配置OpenCV3.1图文详解 OpenCV3.1对硬件加速和移动开发的支持相对于老版本都有了较大改进,支持新的开发工具,更易于扩展,配置方式也比以前简 ...

  7. 深入详解JVM内存模型与JVM参数详细配置

    本系列会持续更新. JVM基本是BAT面试必考的内容,今天我们先从JVM内存模型开启详解整个JVM系列,希望看完整个系列后,可以轻松通过BAT关于JVM的考核. BAT必考JVM系列专题 1.JVM内 ...

  8. 直通BAT必考题系列:深入详解JVM内存模型与JVM参数详细配置

    JVM基本是BAT面试必考的内容,今天我们先从JVM内存模型开启详解整个JVM系列,希望看完整个系列后,可以轻松通过BAT关于JVM的考核. BAT必考JVM系列专题 1.JVM内存模型 2.JVM垃 ...

  9. java 标量替换_详解jvm中的标量替换

    概述 通常在java中创建一个对象,大家都认为是在堆中创建. 在jdk6开始有逃逸分析,标量替换等技术,关于在堆中创建对象不再绝对. 关于标量替换,通过以下几点进行概述: 逃逸分析 标量替换是什么 测 ...

最新文章

  1. Matlab和Modelsim联合仿真的配置
  2. angular学习的一些小笔记(中)之ng-disabled轻松实现按钮是否可点击状态
  3. MapReduce词频统计
  4. nodejs实践录:我的nodejs编码风格
  5. 数字U家,即刻出发!2022联合利华黑客马拉松报名倒计时!
  6. [HAOI2015]树上染色
  7. http后面的双斜杠被转义_【实用干货】双荧光素酶报告基因检测
  8. java 计算 四分位,Java四分位计算方法
  9. 程序员职业规划(一篇来自阿里Java工程师对工作3年左右程序员的职业建议和应该掌握的职业技能)...
  10. matlab求线性规划最大值,matlab线性规划算例
  11. 分形艺术能让你感受上帝的力量——新锐100设计师风达专访
  12. 微信开发者工具小技巧——快速创建小程序的新页面。
  13. one-hot表示和分布式表示
  14. hdu 5148 Cities dp
  15. 启用 DHCP 和静态 IP 共存
  16. 3.Channel详解
  17. 数据库系统概论(第十章数据库恢复技术)
  18. 数据库实验七:存储过程实验
  19. css——指定某个区域可垂直或水平滑动
  20. MySQL多表联合查询

热门文章

  1. https 方式使用git@osc设置密码的方式
  2. WIN2008下找不到proxy的处理方法
  3. Node.js新手教程——怎样实现文件上传功能
  4. 使用XMLHttpRequest实现AJAX
  5. NeHe OpenGL第二十五课:变形
  6. 2006-我都做了什么!
  7. mysql绿色版安装及授权连接
  8. 使用git版本管理时的免密问题
  9. linux系统的空间满的问题
  10. mac自动生成路径问题