Java 虚拟机的堆划分

Java 虚拟机将堆划分为新生代和老年代。其中新生代又被划分为 Eden 区,以及两个大小相同的 Survivor 区。

默认情况下,Java 虚拟机采取一种动态分配的策略,根据对象生成的速率,以及 Survivor 区的使用情况动态调整 Eden 区和 Survivor 区的比例。也可以通过参数 -XX:SurvivorRatio 来固定这个比例。需要注意的是,其中一个 Survivor 区会一直为空,因此比例越低浪费的空间越高。

当调用 new 指令时,它会在 Eden 区中划出一块作为存储对象的内存。由于堆内存是线程共享的,因此直接在这里划分空间是需要进行同步的。否则会出现两个对象公用一段内存的事故。

Java 虚拟机的解决方法是:每个线程可以向 Java 虚拟机申请一段连续的内存,比如 2048 字节,作为线程私有的 TLAB。这个操作需要加锁,线程需要维护两个重要的指针,一个指向 TLAB 中空余内存的起始位置,一个则指向 TLAB 末尾。

然后通过 new 指令,便可以直接通过指针加法来实现,即把指向空余内存位置的指针加上所请求的字节数。如果加法后空余内存指针的值扔小于或等于指向末尾的指针,则代表分配成功。否则,TLAB 以及没有足够的空间来满足本次新建操作。这个时候,便需要当前线程重新申请新的 TLAB。

当 Eden 区的空间耗尽了,这个时候 Java 虚拟机便会触发一次 Minor GC,来收集新生代的垃圾。存活下来的对象,则会被送到 Survivor 区。当发生 MinorGC时,Eden 区和 from 指向的 Survivor 区中的存活对象会被复制到 to 指向的 Survivor 区中,然后交换 from 和 to 指针,以保证下一次 Minor GC 时,to 指向的 Survivor 区还是空的。

Java 虚拟机会记录 Survivor 区中的对象一共被来回复制了几次。如果一个对象被复制 15 次,那么该对象将被晋升至老年代。如果单个 Survivor 区已经被占用了 50%,那么较高复制次数的对象也会被晋升至老年代。

Minor GC 有一个问题,那就是老年代的对象可能引用新生代的对象。在标记存活对象的时候,我们需要扫描老年代中的对象。如果该对象拥有对新生代对象的引用,那么这个引用也会被作为 GC Roots。这样的话,就相当于进行了一次全堆扫描。

卡表

针对上述的问题,HotSpot 给出了一种解决方案叫做卡表。该技术将整个堆划分为一个个大小为 512 字节的卡,并且维护一个卡表,用来存储每张卡的一个标示位。这个标示位代表对应的卡是否可能存在指向新生代对象的引用。如果可能存在,那么我们就认为这张卡是脏的。

在进行 Minor GC 的时候,我们不用扫描整个老年代,而是在卡表中寻找脏卡,并将脏卡中的对象加入到 Minor GC 的 GC Roots 里。当完成所有脏卡的扫描之后,Java 虚拟机便会将所有脏卡的标示位清零。

上述总结介绍了用卡表这种方式解决全堆扫描效率低下的问题,置于如何标记脏卡,如何更新脏卡就不做深入总结了。

问答

Q:请问JVM分代收集新生代对象进入老年代,年龄为什么是15而不是其他的?

HotSpot会在对象头中的标记字段里记录年龄,分配到的空间只有4位,最多只能记录到15

Q:GC ROOT到底指的是对象本身,还是引用?

严格来说应该是对象。像局部变量中存放的引用只是导致对象成为GC roots的原因。我个人倾向于将这些引用作为GC roots,因为GC是从这些地方出发开始探索的。看各人理解方便吧。

总结

本文创作灵感来源于 极客时间 郑雨迪老师的《深入拆解 Java 虚拟机》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。

关注本人公众号,第一时间获取最新文章发布,每日更新一篇技术文章。

12 JVM 垃圾回收(下)的更多相关文章

  1. JDK分析工具&JVM垃圾回收(转)

    转自:http://blog.163.com/itjin45@126/blog/static/10510751320144201519454/ 官方手册:http://docs.oracle.com/ ...

  2. JVM基础系列第8讲:JVM 垃圾回收机制

    在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...

  3. Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法

    在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...

  4. JVM垃圾回收?看这一篇就够了!

    深入理解JVM垃圾回收机制 1.垃圾回收需要解决的问题及解决的办法总览 1.如何判定对象为垃圾对象 引用计数法 可达性分析法 2.如何回收 回收策略 标记-清除算法 复制算法 标记-整理算法 分带收集 ...

  5. JVM垃圾回收重要理论剖析【纯理论】

    JVM学习到这里,终于到学习最兴奋的地方了---垃圾回收,在学习它之前还得对JVM垃圾回收相关理论知识进行了解,然后再通过实践来加深对理论的理解,下面直接开始了解相关的理论: JVM运行时内存数据区域 ...

  6. JVM内存管理和JVM垃圾回收机制

    JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...

  7. 老李分享:jvm垃圾回收

    老李分享:jvm垃圾回收   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478 ...

  8. jvm - 垃圾回收

    jvm - 垃圾回收 注意 : 本系列文章为学习系列,部分内容会取自相关书籍或者网络资源,在文章中间和末尾处会有标注 垃圾回收的意义 它使得java程序员不再时时刻刻的关注内存管理方面的工作. 垃圾回 ...

  9. Java虚拟机学习笔记——JVM垃圾回收机制

    Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...

随机推荐

  1. POJ - 3685 Matrix

    二分kth,答案满足的条件为:m ≤ 小于等于x的值数cntx.x和cntx单调不减,随着x增大,条件成立可表示为:0001111. 本地打一个小型的表可以发现列编号j固定时候,目标函数f(i,j)似 ...

  2. Android(java)学习笔记84:SQLiteDatabase的query方法参数

    1. SQLiteDatabase的query方法: public Cursor query (boolean distinct, String table, String[] columns, St ...

  3. SpringMVC+Hibernate框架快速搭建

    1.  新建Maven项目springmvc 2.   pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" ...

  4. python之道12

    整理今天笔记,课上代码最少敲3遍. 用列表推导式做下列小题 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 l = ['wusir', 'laonanhai', 'aa', 'b', 'tai ...

  5. CUDA常见问题与解答

    源 1.在SDK自带的例子程序中,发现SRC文件珜下有.cpp文件和.cu文件.这两种文件的关系和各自的作用是什么呀? 答:SDK自带例子中的.cpp文件主要是一些CPU端处理,或者是使用CPU计算对 ...

  6. mysql 获取系统时间的下一天 年-月-日 时:分:秒

    DAY) as date

  7. vue-transition动画

    vue-transition动画 官网API: https://cn.vuejs.org/v2/guide/transitions.html demo点击显示与消失 <div id=" ...

  8. Android驱动开发读书笔记六

    第六章 Linux 驱动的工作和访问方式是 Linux 的亮点之一,Linux 系统将每一个驱动都映射成一个文件.这些文件称为设备文件或驱动文件,都保存在/dev目录中,由于大多数Linux驱动都有与 ...

  9. MySQL - FIND_IN_SET 函数使用方法

    SELECT * FROM xxxTableName x WHERE FIND_IN_SET(x.id, '1,2,3,4,5,6,7,8');   如上查询,意为:xxxTableName 表中 x ...

  10. asp.net 中 UpdataPanel 的使用注意点

    1. 在UpdataPanel 前必须加上asp:ScriptManager的控件,保证页面能够正常显示