🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客
🔥温馨提示:划到文末发现专栏彩蛋 点击这里直接传送
🔥本篇概览:详细讲解了运行时数据区组成的最大一块——堆。堆与JVM的对应关系、堆与栈的关系以及堆的空间划分。🌈⭕🔥
【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】
🌈引出:
前一篇章:《剑指JVM》——第6章——本地方法栈——运行时数据区篇12-CSDN博客
🌈章节引出:
前面章节讲了栈是运行时的单位(准确的说是线程,而栈又是线程的数据存储单位),栈解决程序的运行问题,即程序如何执行,或者说如处理数据。栈中处理的数据主要来源于堆(Heap),堆是存储的单位,堆解决的是数据存储的问题,即数据怎么放、放在哪儿。
堆是JVM所管理的内存中最大的一块区域,在工作中遇到的大部分问题来自于堆空间,所以更好地了解堆内存结构就显得非常必要。本章将会重点讲解堆内存的内部结构以及对象在堆空间中的分配策略。
🌈章节速览:
7.1 堆的核心概述
7.1.1 JVM实例与堆内存的对应关系
在JVM 中,堆是各个线程共享的运行时内存区域,也是供所有类实例和数组对象分配内存的区域。一个JVM实例只存在一个堆内存,我们创建类HeapDemo和HeapDemol说明个 JVM 实例只有一个堆内存,如代码清单7-1和代码清单 7-2所示:
内存大小10M -Xms10M -Xmx10M
public class HeapDemo {
public static void main(String[] args) {
System.out.println("start...");
try {
Thread.sleep(1000000); // 使当前线程暂停 1000000 毫秒(约 16 分钟多)
} catch (InterruptedException e) { // 处理线程睡眠被中断的异常
e.printStackTrace(); // 打印异常的堆栈跟踪信息
}
System.out.println("end...");
}
}
内存大小20M -Xms20M -Xmx20M
public class HeapDemo1 {
public static void main(String[] args) {
System.out.println("start...");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end...");
}
}
上面的代码很简单,除了内存设置,其他完全一样,启动程序,使程序等待1000秒。两段代码的内存大小设置是不一样的:HeapDemo使用参数Xms和Xmx设置内存大小为10MB; HeapDemo1 使用参数Xms 和Xmx 设置内存大小为 20MB。这里大家知道参数Xms 和 Xmx 是用来设置内存大小即可,后面我们会详细介绍。
启动完程序之后,此时两个Java程序对应两个JVM 实例,对应的进程id(图7-1中pid)分别是111348和101564,通过JDK自带工具jvisualvm来查看程序的堆空间,该工具会在后续的章节详细介绍,如图7-1所示:
从图7-1中可以看到两个应用程序对应不同的堆空间分配,各自对应的堆内存分别是10MB 和 20MB,也对应上了参数Xms和Xmx的设置。上述试验结果说明,(每个应用程序对应唯一的堆空间,即每个 JVM 实例对应唯一的堆空间。
堆在JVM启动的时候被创建,其空间如图 7-2 所示,堆也是 Java 内存管理的核心区域。大小也随之被确定。堆是JVM 管理的最大一块内存空间,其大小是可以根据参数调节的,它可以处于物理上不连续的内存空间中,但在逻辑上应该被视为连续的。底层还是物理空间。
7.1.2 堆与栈的关系
🔥代码示例:
堆中存放的是对象,栈帧中保存的是对象引用,这个引用指向对象在堆中的位置。下面的案例用于说明栈和堆之间的关系,如代码清单 7-3 所示:
public class SimpleHeap {
private int id; // 属性、成员变量
public SimpleHeap(int id) {
this.id = id;
}
public void show() {
System.out.println("My ID is " + id);
}
public static void main(String[] args) {
SimpleHeap s1 = new SimpleHeap(1);
SimpleHeap s2 = new SimpleHeap(2);
s1.show();
s2.show();
}
}
PS:程序的main函数
记住一点,对象的组成没有main函数也也可以,只不过main函数是程序执行的起点罢了。标准的对象的定义是没有main函数的。
如图 7-3 所示,展示了 Java 栈和堆之间的关系。Java 栈中的s1 和 s2分别是堆中 s1 实例和 s2 实例的引用:
代码中的 main()方法与字节码对应的关系如图 7-4所示,关于如何理解字节码的含义,后面的章节会详细介绍,比如new指令用来开辟堆空间,创建对象。
每一个new就是对应在堆中开创一份空间存放对象数据。
7.1.3 JVM堆空间划分
在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。堆也是GC(Garbage Collector,垃圾收集器)执行垃圾回收的重点区域。现代垃圾收集器大部分都基于分代收集理论设计,这是因为堆内存也是分代划分区域的,堆内存分为新生代(又叫年轻代)和老年代。
(1)新生代,英文全称Young Generation Space,简称为Young或New。该区域又分为Eden 区和 Survivor 区。Survivor 又分为Survivor0 区 和 Survivor1 区。Survivor0 和 Survivor1也可以叫作 from 区和 to 区,简写为 S0 区和 S1 区。
(2)老年代,也称为养老区,英文全称Tenured Generation Space,简称为 Old或 Tenured。
堆内存区域规划如图 7-5 所示。
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖
热门专栏推荐
🌈🌈计算机科学入门系列 关注走一波💕💕
🌈🌈CSAPP深入理解计算机原理 关注走一波💕💕
🌈🌈微服务项目之黑马头条 关注走一波💕💕
🌈🌈redis深度项目之黑马点评 关注走一波💕💕
🌈🌈JAVA面试八股文系列专栏 关注走一波💕💕
🌈🌈JAVA基础试题集精讲 关注走一波💕💕
🌈🌈代码随想录精讲200题 关注走一波💕💕
总栏
🌈🌈JAVA基础要夯牢 关注走一波💕💕
🌈🌈JAVA后端技术栈 关注走一波💕💕
🌈🌈JAVA面试八股文 关注走一波💕💕
🌈🌈JAVA项目(含源码深度剖析) 关注走一波💕💕
🌈🌈计算机四件套 关注走一波💕💕
🌈🌈数据结构与算法 关注走一波💕💕
🌈🌈必知必会工具集 关注走一波💕💕
🌈🌈书籍网课笔记汇总 关注走一波💕💕
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!