JVM--堆区

堆的基本概念

特点:

  • 线程共享
  • 存放对象实例
  • 是Java内存区域中最大的部分
  • 是GC的最主要的区域

Java堆是虚拟机所管理的内存中最大的一块,此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这块区域是“线程共享”的。

Java堆是垃圾收集器管理的主要区域,因此也被称作“GC堆”。由于现在垃圾收集器基本采用分代收集算法,所以Java堆还可以细分为新生代和老年代。Java堆可以处于物理上不连续的内存空间中,只要逻辑上连续即可。如果堆中没有内存完成实例分配,并且堆也无法扩展时,将会抛出OutOfMemoryError异常。

新生代和年老代

堆区被分为新生代和年老代。这样分是为了方便GC操作。

一般对象都在新生代创建,因为Java程序中的对象绝大部分是朝生夕死的,所以新生代中每次GC都会有大量对象被回收,新生代的GC操作也更频繁。

年老代中一般存放那些对象存活率高、生命周期长的对象。一般位于新生代中的对象满足某些条件(比如大对象、经历了几次新生代GC还存活的对象等)会转到年老代中去。年老代中GC不频繁,但GC效率要比新生代中GC慢许多。

Minor GC和Full GC

  • Minor GC(新生代GC):指发生在新生代的垃圾回收动作,因为Java对象一般满足朝生夕死的条件,所以Minor GC非常频繁,一般回收速度也比较快。
  • Full GC / Major GC(年老代GC):发生在年老代的GC,一般会伴随至少一次的Minor GC。Full GC一般比Minor GC慢10倍以上。

对象分配策略

既然堆区被分为新生代和年老代,那么对象是如何在这两个区域分配的?最普遍的几条策略如下:

1  对象优先在Eden分配

新生代更细分为一个Eden区和两个Survivor区,具体这些分区的作用在GC算法中详细讲解。这里只要了解对象优先在新生代分配即可。

2  大对象直接进入老年代

所谓的大对象是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组。经常出现大对象容易导致内存还有不少空间的时候提前触发GC。

虚拟机提供一个配置参数,可以令所有大于这个值的对象直接在年老代分配。

3  长期存活的对象将进入年老代

虚拟机给每一个对象设置了一个对象年龄计数器。如果对象在Eden出生并经历了一次Minor GC后仍然存活,那么她会被置入Survivor区(要保证Survivor能容纳),并且年龄置为1。对象在Survivor区每熬过一个Minor GC就增加1岁,当年龄增加到一个值(默认15),会转入老年代。

4  动态对象年龄判定

为了能更好地适应不同程序的内存情况,虚拟机提供动态对象年龄判定机制。如果Survivor区中相同年龄所有对象的总和大于等于Survivor空间的一半,那么所有大于等于该年龄的对象直接进入年老代。

浅堆和深堆

浅堆(Shallow Heap)和深堆(Retained Heap)是两个非常重要的概念,注意这里的“堆”和上面的堆意义不一样。这个“堆”是针对单个对象而言的。

  • 浅堆表示一个对象结构所占用的内存大小
  • 深堆表示一个对象被GC回收后,可真实释放的内存大小

比如Java中String类型结构包含三个字段:hash32、hash和一个ref引用,该引用保存一个静态的字符串地址。那么2个int值共占8字节,对象引用占用4字节,对象头8字节,合计20字节,向8字节对齐,故占24字节。所以不论String保存的是什么字符串,它占用的内存都是24字节。

深堆表示一个对象被GC回收后,可真实释放的内存大小。先来理解保留集:一个对象的保留集是一个对象集合,集合中的所有对象都可以在该对象被回收之后被回收。然后说深堆,深堆是指对象的保留集中所有的对象的浅堆大小之和。

注意:浅堆指对象本身占用的内存,不包括其内部引用对象的大小。一个对象的深堆指只能通过该对象访问到的(直接或间接)所有对象的浅堆之和,即对象被回收后,可以释放的真实空间。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 支配树(Dominator Tree)

    在使用MAT分析项目的内存泄漏问题时,其中有一个支配树(Dominator)视图。如果我们把Java对象之间的引用关系看做一张有向图(可以存在环)的话,对象的支...

    SuperHeroes
  • JVM--对象回收

    Java运行时数据区包括:程序计数器、虚拟机栈、本地方法栈、Java堆和方法区。这里面程序计数器、虚拟机栈和本地方法栈是线程私有的,当线程结束或者方法退出时其内...

    SuperHeroes
  • 发布与逸出

    SuperHeroes
  • Java堆

    Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。这个区域是用来存放对象实例的,几乎所有对象实例都会在这里分配内存。平常我们听说的垃圾收集、GC等...

    Java学习录
  • “看毛片”算法的那些事

    前两天分享了《0Day技术分析》系列文章,今天就不再分享,明天再见面吧。今天带来的是饼哥自己文章,直接上干货吧。还有就是从下礼拜一起,有新的专题出现,大家可以猜...

    zhisheng
  • Java到底是不是一种纯面向对象语言?

    Java——是否确实的 “纯面向对象”?让我们深入到Java的世界,试图来证实它。

    哲洛不闹
  • 程序员要拥抱变化,聊聊 Android 即将支持的 Java 8

    Java 9预计今年也会正式发布,Java 8这个最具变革性且变革性最适于GUI程序的版本,Android终于准备正式支持。从自己开发JavaFx的感受,说一说...

    WeTest质量开放平台团队
  • CMS GC:CMS 废弃了,该怎么办呢?

    流行的 CMS( Concurrent Mark Sweep) GC 算法在 JDK 9 中被废弃了。根据 JEP-291 中的说明,为了减轻 GC 代码的维护...

    涤生
  • (原创)详解KMP算法

    KMP算法应该是每一本《数据结构》书都会讲的,算是知名度最高的算法之一了,但很可惜,我大二那年压根就没看懂过~~~ 之后也在很多地方也都经常看到讲解KMP算法的...

    marsggbo
  • 《Java编程思想》第一章:对象导论 原

        本人的笔记风格是,将书中的重要知识点摘抄出来,如果是特别转弯的话,本人会用自己的理解进行说明。从现在开始讲读书笔记一篇一篇的抛出来,供大家参阅学习讨论,...

    云飞扬

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动