跳到主要内容

JVM 堆内存

1. 前言

本节主要讲解运行时数据区的堆内存。本节主要知识点如下:

  • 掌握堆内存空间结构图,从总体层面认识堆内存,为本节重点内容之一;
  • 了解 JVM 堆空间的基本概念,为本节的基础知识点;
  • 了解堆内存的分代概念,年轻代,eden区,from/to,幸存者及老年代,为本节核心知识点,后续对垃圾回收讲解时,大部分的回收都是发生在堆内存中,掌握分代概念是学习垃圾回收机制的必要前提。

2. 堆内存结构

堆内存是运行时数据区中非常重要的结构,实例对象会存放于堆内存中。在后续小节中,我们讲解 GC 垃圾回收器,绝大多数的垃圾回收都发生在堆内存中,因此对于 JVM 来说,堆内存占据着十分重要的且不可替代的位置。

我们先来看下堆内存的结构图,初步了解堆内存的整体内存划分。

图片描述

从上图可以看到如下几个要点:

  • 堆内存从结构上来说分为年轻代(YoungGen)和老年代(OldGen)两部分;
  • 年轻代(YoungGen)又可以分为生成区(Eden)和幸存者区(Survivor)两部分;
  • 幸存者区(Survivor)又可细分为 S0区(from space)和 S1区 (to space)两部分。

从图中,我们能够大体了解堆内存的结构划分,后文在讲解分代概念时,我们会提供更加直观,更加清晰的内存结构图。

3. 什么是堆内存

物理层面:从物理层面(硬件层面)来说,当 Java 程序开始运行时,JVM 会从操作系统获取一些内存。JVM 使用这些内存,这些内存的一部分就是堆内存。

Java层面:从开发层面来说,堆内存通常在存储地址的底层,向上排列。当一个对象通过 new 关键字或通过其他方式创建后,对象从堆中获得内存。当对象不再使用了,被当做垃圾回收掉后,这些内存又重新回到堆内存中。

总结来说,堆内存是JVM启动时,从操作系统获取的一片内存空间,他主要用于存放实例对象本身,创建完成的对象会放置到堆内存中。

4. 堆内存的分代概念

从上文堆内存的结构图中,我们看到了比较多的JVM堆内存中的专有名词,比如:年轻代,老年代。那么对于堆内存来说,分代是什么意思呢?为什么要进行分代呢?

分代:将堆内存从概念层面进行模块划分,总体分为两大部分,年轻代和老年代。从物理层面将堆内存进行内存容量划分,一部分分给年轻代,一部分分给老年代。这就是我们所说的分代。

分代的意义:易于堆内存分类管理,易于垃圾回收。类似于我们经常使用的 Windows 操作系统,我们会将物理磁盘划出一部分存储空间作为用户系统安装盘(如 C 盘),我们还极大可能将剩余的磁盘空间划分为 C, D, E 等磁盘,用于存储同一类型的数据。

  • 易于管理:对于堆空间的分代也是如此,比如新创建的对象会进入年轻代(YoungGen)的生成区(Eden),生命周期未结束的且可达的对象,在经历多次垃圾回收之后,会存放入老年代(OldGen),这就是分类管理;
  • 易于垃圾回收:将对象根据存活概率进行分类,对存活时间长的对象,放到固定区,从而减少扫描垃圾时间及 GC 频率。针对分类进行不同的垃圾回收算法,对算法扬长避短。

Tips:关于上文提到的垃圾回收部分的知识,我们会在后边的章节做专门的、详细的讲解,此处我们先做了解即可。

5. 堆内存结构详解

讲解完分代的概念,我们来对堆内存中的不同的代,不同的内存空间的作用进行更加详细的讲解。讲解之前,我们来看下如下示意图,更加直观的了解堆内存结构。

图片描述

堆内存每个模块之间的关系及各自的特点概述如下:

  • JVM 内存划分为堆内存和非堆内存,堆内存分为年轻代(YoungGen)、老年代(OldGen);
  • 年轻代又分为 Eden 和 Survivor 区。Survivor 区由 FromSpace 和 ToSpace 组成。Eden 区占大容量,Survivor 两个区占小容量,默认比例是 8:1:1;
  • 堆内存存放的是对象,垃圾收集器就是收集这些对象,然后根据 GC 算法回收;
  • 新生成的对象首先放到年轻代 Eden 区,当 Eden 空间满了,触发 Minor GC,存活下来的对象移动到Survivor0 区,Survivor0 区满后触发执行 Minor GC,Survivor0 区存活对象移动到 Suvivor1 区,这样保证了一段时间内总有一个 survivor 区为空。经过多次 Minor GC 仍然存活的对象移动到老年代;
  • 老年代存储长期存活的对象,GC 期间会停止所有线程等待 GC 完成,所以对响应要求高的应用尽量减少发生 Major GC,避免响应超时。

Tips:关于上文提到的垃圾回收部分的知识,我们会在后边的章节做专门的、详细的讲解,此处我们主要关注在堆内存的每个模块的概念,特点及作用。对于垃圾回收部分的知识,我们后续再进行学习。

6. 小结

本节主要讲解了运行时数据区里边的堆内存,堆内存是一块共享内存区域,在运行时数据区占据着十分重要的位置。我们了解了堆内存里的分代概念,并从示意图中直观的感受了堆内存的结构。我们了解了堆内存中不同内存空间模块的作用、特点及意义。这都是非常重要的知识点。

由于垃圾回收绝大多数都是发生在堆内存中,因此在课程讲解的过程中,多少会涉及到垃圾回收的一些概念,此处如果不能理解的学习者,可以在学习完垃圾回收器后再次理解目前不能够掌握的知识。