Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Java进阶】Java内存模型

【Java进阶】Java内存模型

作者头像
全栈开发日记
发布于 2025-06-15 05:04:48
发布于 2025-06-15 05:04:48
14200
代码可运行
举报
文章被收录于专栏:全栈开发日记全栈开发日记
运行总次数:0
代码可运行

下面的内容如果我没有专门提及Java版本,则都是以Java8+为例,已经过期的Java7-就不过多研究了。

内容仅为个人观点,如果有不对的请留言互相学习。

在Java8+中内存模型中主要包括:

① 堆内存(年轻代、老年代、字符串常量池)

② 其他的非堆内存,包括了元空间(类的元数据、运行时常量池)、代码缓存、线程栈

img
img

img

1.1. 字符串常量池和运行时常量池

这两个都是常量池,为什么一个在堆内存中,另一个在元空间中呢?

运行时常量池中存储的是字符串常量池的引用,可以理解为你把文件存到了D盘,但给这个文件创建了一个快捷方式,把快捷方式存在C盘,这样你就可以直接在C盘快速的访问D盘中的文件了。

基本类型常量(如intfloat)会嵌入代码或存于运行时常量池。

假设我们有以下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
String s = "hello";

它的加载方式如下图所示:

img
img

img

在编译阶段时,会先根据.class文件生成符号引用的记录。

在类加载阶段,把这个生成的符号引用记录加载到运行时常量池中,此时还没有创建实际的字符串。

在运行阶段,JVM才会根据符号引用记录去字符串常量池中创建,就相当于是运行之前,JVM假装已经有了这个字符串(反正也暂时不用),运行的时候才去真的创建。

注意:这里有一个误区,String s = "hello"String s = new String("hello")加载方式不一样。后者因为使用了new,所以在堆中创建了两个对象。

1.2. 年轻代和老年代

年轻代和老年代是堆内存的主要区域,每一个新建对象都会先进入年轻代中的Eden 区,当Eden 区满时会触发Minor GC,GC过后Eden 区幸存下来以及非空闲幸存者区的对象会通过复制算法复制到空闲的幸存者区(S0和S1始终会保持其中一个为空),复制完成后Eden区和原非空闲幸存者区对象会被清空。

年轻代内存分布图
年轻代内存分布图

年轻代内存分布图

每一次 Minor GC年轻代中存活的对象年龄都会+1,当幸存者区中的对象年龄≥15时会晋升至老年代中。

在Java8中会动态调整晋升阈值,如果某年龄对象总大小 > Survivor 区 50%,则≥该年龄的对象直接晋升。

对象在堆内存中完整生命周期
对象在堆内存中完整生命周期

对象在堆内存中完整生命周期

这个是理想情况下是这样的,但有时候就是不太理想,比如创建的对象太大幸存者区放不下的情况都会导致对象直接被放到了老年代中。

而晋升到老年代的对象太多时,就会导致频繁的Full GC,,导致性能下降甚至OOM,如果确实业务需要,可以考虑增加堆空间大小(-Xmx)或者调整老年代的比例(默认老年代和年轻代是2/1)。

1.3. 永久代和元空间

Java8之前的版本中还有一个叫永久代的东西,在Java8中大部分作用被元空间取代了,但也并不是替换这么简单,Java8之前的永久代跟年轻代、老年代一样是在堆内存中,现在的元空间并没有在堆内存中。

由于永久代是堆内存的一部分,所以它的内存空间是固定的。而元空间并不受堆内存的影响,它是动态扩展,你电脑系统的内存有多大它就能用多大,当然你也可以通过配置JVM参数-XX:MaxMetaspaceSize设置上限。

上文说到的字符串常量池在Java8之前是在永久代中的,Java8之后字符串常量池的“老大”永久代被干掉了,字符串常量池身当大哥了,直接属于堆内存中的一块空间了。

1.4. GC行为

上文中多次出现Minor GC和Full GC并不是一种具体的垃圾回收算法,而是指一种行为,Minor GC是指局部回收,一般用在年轻代中的回收,所以也被称 Young GC。而Full GC是指全局回收,整个堆内存和元空间都会被回收。

在GC过程中会STW(Stop-The-World),就是说这个期间会把正在运行的线程暂停,是为了对象引用不会在这期间修改,可以类比一个清洁工来办公室清理垃圾,但得让你们腾地方,就会导致此期间无法工作。一般Minor GC行为的STW时间是毫秒级,但Full GC是全堆清理,它的STW时间一般都得秒级,甚至能达到30s以上。

除了上述两种GC行为,还有另一种Java9+才应用的Mixed GC行为,即混合行为。就是为了防止上述说的Full GC时秒级的STW。Mixed GC能让垃圾回收像回收年轻代一样回收老年代,不需要全堆的停顿,一般是将回收过程分多次进行,这样也可以分摊停顿时间。

但被用的最多的Java8当老年代满时,就会触发Full GC,不会进行Mixed GC,要在Java 8中使用Mixed GC需要手动配置,并且不太稳定,建议是直接升级JDK版本到JDK11+。

如果需要在Java8中使用Mixed GC行为,可以通过配置如下参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-XX:+UseG1GC # 使用G1垃圾回收器
-XX:InitiatingHeapOccupancyPercent=45 # 触发并发标记的老年代阈值(老年代占堆内存比例)
-XX:G1MixedGCLiveThresholdPercent=85 # Mixed GC回收区域的存活率上限(存活对象 > 85% 的区域不回收)
-XX:G1HeapWastePercent=10 # 碎片空间占堆内存比例,也就是允许10%空间浪费

调优指南

① -XX:G1MixedGCLiveThresholdPercent=85可能会因为太多区域被跳过,导致每次GC堆释放空间太少,从而导致频繁的GC。需要根据自己系统业务,判断是否会存在这个情况来调整比例。

② -XX:G1HeapWastePercent=10可能会导致堆中有大量碎片空间,但还没有达到10%的这个阈值,可以根据自己系统堆空间大小来实际调整。

1.5. GC类型

六大GC类型垃圾收集器对比表

收集器

年轻代算法

老年代算法

优势

适用场景

Serial GC

复制

标记-整理

单线程低开销

客户端/嵌入式(资源受限)

Parallel GC

复制(多线程)

标记-整理(多线程)

高吞吐量

计算密集型后端

CMS

复制

并发标记-清除

低停顿(老年代)

响应敏感的 Web 服务(已废弃)

G1 GC

复制(Region)

复制+标记-整理

平衡吞吐与停顿

大堆内存(6GB~16GB)

ZGC

并发复制

并发复制

亚毫秒停顿

超大堆(TB级)、低延迟要求

Shenandoah GC

并发复制

并发复制

低停顿+高吞吐

大堆内存、混合负载

JDK 8 默认:Parallel GC(吞吐优先)

JDK 9~14 默认:G1 GC(平衡型)

JDK 15+ :ZGC/Shenandoah(极致低延迟)

下面是主要的几个GC收集器的STW停顿时间

img
img

主要GC收集器的STW停顿时间


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈开发日记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
JVM常见面试题(四):垃圾回收
当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化"的技术实施必要的监控和调节。
寻求出路的程序媛
2024/11/24
2840
JVM常见面试题(四):垃圾回收
深入理解Java中的Garbage Collection
最近由于系统业务量比较大,从生产的GC日志(结合Pinpoint)来看,需要对部分系统进行GC调优。但是鉴于以往不是专门做这一块,但是一直都有零散的积累,这里做一个相对全面的总结。本文只针对HotSpot VM也就是Oracle Hotspot VM或者OpenJDK Hotspot VM,版本为Java8,其他VM不一定适用。
Throwable
2020/06/23
7990
深入理解Java中的Garbage Collection
JVM内存模型和垃圾回收机制
有的博客称方法区是永久代,那是因为前者是JVM的规范,而后者则是JVM规范的一种实现,并且只有HotSpot才有永久代,
全菜工程师小辉
2019/08/16
7710
JVM内存管理
Java内存管理是一项持续的挑战,同时也是锻造出可拓展应用的必备技能。本质上,Java内存管理就是一个为新对象分配内存和释放无用对象内存的过程。
码代码的陈同学
2018/06/03
2.3K0
JVM内存管理
java(9)-深入浅出GC垃圾回收机制
1、本文了解GC垃圾回收机制,深入理解GC后才明白,为啥FGC会导致stop-the-world。 2、了解GC算法。
黄规速
2022/04/14
1.1K0
java(9)-深入浅出GC垃圾回收机制
Java虚拟机
程序计数器不会产生StackOverflowError和OutOfMemoryError.
知识浅谈
2022/01/01
1K0
面试官:说说JVM内存整体结构?
Java 虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应的,这些与线程一一对应的数据区域会随着线程开始和结束而创建和销毁。
鲁大猿
2024/01/04
2940
面试官:说说JVM内存整体结构?
自动的内存管理系统实操手册——Java垃圾回收篇
导语 | 现代高级编程语言管理内存的方式分自动和手动两种。手动管理内存的典型代表是C和C++,编写代码过程中需要主动申请或者释放内存;而PHP、Java 和Go等语言使用自动的内存管理系统,由内存分配器和垃圾收集器来代为分配和回收内存,其中垃圾收集器就是我们常说的GC。本文中,腾讯后台开发工程师汪汇从原理出发,介绍 Java 和Golang垃圾回收算法,并从原理上对他们做一个对比。今天先向大家分享 Java 垃圾回收算法。 一、 垃圾回收区域及划分 在介绍 Java 垃圾回收之前,我们需要了解 Jav
腾讯云开发者
2021/08/04
5810
Java基础知识:JVM内存结构
jvm将虚拟机分为 5大区域 ,程序计数器、虚拟机栈、本地方法栈、java堆、方法区;
DioxideCN
2022/08/05
8060
Java基础知识:JVM内存结构
JVM 内存模型面试总结
就是 JAVA 虚拟机, 它只识别 .class 类型文件,它能够将 class 文件中的字节码指令进行识别并调用操作系统向上的 API 完成动作。
Tim在路上
2020/08/04
5850
2万字长文包教包会 JVM 内存结构
内存是非常重要的系统资源,是硬盘和 CPU 的中间仓库及桥梁,承载着操作系统和应用程序的实时运行。JVM 内存布局规定了 Java 在运行过程中内存申请、分配、管理的策略,保证了 JVM 的高效稳定运行。不同的 JVM 对于内存的划分方式和管理机制存在着部分差异。
Java3y
2020/07/09
5390
2万字长文包教包会 JVM 内存结构
JVM-01Java内存区域与内存溢出异常(上)【运行时区域数据】
在内存管理领域 ,C/C++内存管理由开发人员管理,既拥有每一个对象的所有权,还必须负责维护每一个对象生命从开始到终结的责任
小小工匠
2021/08/16
4250
JVM的内存管理(堆内存)
也称heap堆区。堆是jvm内存中占用空间最大的一个区域。主要分为新生代、老年代、永久代(jdk1.8以后叫元空间,到1.9以后又被移除)
用户7410760
2024/12/14
3220
JVM的内存管理(堆内存)
Java内存区域和GC机制
  Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代 码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。概括地说,该机制对 JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver Stop)的保证JVM中的内存空间,放置出现内存泄露和溢出问题。
Java团长
2018/08/06
5540
JVM基础
参考链接:https://www.cnblogs.com/yrxing/p/14464799.html
橘子又加强了么
2023/09/25
3170
面霸篇:JVM 21 问与答
jvm将虚拟机分为5大区域,程序计数器、虚拟机栈、本地方法栈、java堆、方法区;
码哥字节
2021/08/23
5190
面霸篇:JVM 21 问与答
「周一电台 x 训练营」从三道题开始,认识Java内存
几乎所有的对象实例以及数组在堆里分配内存。Java堆还是垃圾收集器(Garbage Collection,GC)管理的主要区域,因此我们也可以叫它GC堆,请勿叫做垃圾堆!
翊君
2022/03/15
3220
「周一电台 x 训练营」从三道题开始,认识Java内存
面试:精通Java;面试官:来讲一下JVM虚拟机内存模型的最底层原理,必须说详细说清楚,知其所以然。看完后,你还敢在简历上写精通Java吗?
精通Java?来看看下面这些底层中的底层原理你是否知道吧。 提到JVM必不可少的就得谈到它的内存模型,根据 JVM 规范,JVM 内存共分为虚拟机栈VM stack、堆heap、方法区Method Area、程序计数器Program Counter Register、本地方法栈Native Method Stack五个部分。如下图,咋们分别对这五个区域进行详细的原理讲解。(为节省读者的时间,方便大家理解记忆,笔者把全部知识点分层分段,用较短的语言去描述,言简意赅,句句都是重点。)
全栈程序员站长
2022/08/26
4150
面试:精通Java;面试官:来讲一下JVM虚拟机内存模型的最底层原理,必须说详细说清楚,知其所以然。看完后,你还敢在简历上写精通Java吗?
醒酒菜:动画图解核心内存区--堆
端午佳节一下子就过完了,大家是不是还沉迷在假期的欢乐气氛中无法自拔?今天阿Q为大家准备了上好的“醒酒菜”——JVM运行时数据区的核心内存区——堆。
阿Q说代码
2021/06/22
4730
醒酒菜:动画图解核心内存区--堆
基于JDK8的JVM内存模型详解与GC策略
在JDK 8中,永久代被删除,类元数据在本机内存中分配。默认情况下,可用于类元数据的本机内存量是无限制的。使用该选项MaxMetaspaceSize可以为用于类元数据的本机内存量设置上限。
yingzi_code
2019/08/31
2.8K0
相关推荐
JVM常见面试题(四):垃圾回收
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验