news 2026/7/1 10:17:00

JVM 内存到底分了哪几块——我的学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JVM 内存到底分了哪几块——我的学习笔记

说在前面:我是一个刚接触 JVM 的新手。这篇文章是我在啃资料、看视频、反复问自己"这个玩意儿到底有什么用"之后,整理出来的笔记。我不会说这个很简单——因为对我真不简单。如果你也是刚开始学,希望能帮到你。


我是怎么开始学这个的

事情是这样的。之前写 Java 代码,遇到过一个报错叫OutOfMemoryError: Java heap space,我当时看了两眼一黑,只知道"哦,内存不够了"。但是内存不够了为什么会是这个报错,为什么有的报错叫StackOverflowError有的叫Metaspace,我完全不知道。

后来跟朋友聊,他说你先不要管报错,你先搞清楚 JVM 把内存分成了哪几块。

好,我就从这个开始学。


JVM 把内存分成了五块(JDK 8)

我先说结论,然后再一块一块说。

JDK 8 里面,JVM 运行时内存分成了五个区域:

  1. 程序计数器(Program Counter Register)
  2. Java 虚拟机栈(JVM Stack)
  3. 本地方法栈(Native Method Stack)
  4. Java 堆(Heap)
  5. 元空间(Metaspace)

还有一个叫直接内存(Direct Memory),这个不属于 JVM 管,但也算内存的一部分,后面会提。

乍一看五个名字挺吓人的,但别怕,我一个一个拆开讲。


程序计数器——最小的一块,也是唯一不会溢出的地方

这个东西的名字听着很厉害,其实它的功能挺简单:记录当前线程执行到哪一行字节码了。

你可以把它理解成你看书的时候手里夹的那张书签。你读的是哪一页、哪一行,书签帮你记着。线程也一样,CPU 把它的时间片切走了,它要去干别的线程,等切回来的时候,程序计数器帮它找到刚才读到哪儿了。

有两个点我觉得有意思:

  • 如果执行的是Native 方法(也就是本地方法,比如 C 写的代码),程序计数器的值是undefined。因为 native 方法走的是本地指令,不是 JVM 的字节码,没法用这个计数器来记。
  • 它是 JVM 五大区域里唯一不会发生 OutOfMemoryError的地方。规范里就没给它留这个异常。

为什么它是线程私有的?因为每个线程各读各的代码,各走各的执行路径。如果共用一个计数器,切换回来就不知道切到谁那儿了。所以每个线程自己管自己的。


Java 虚拟机栈——和方法调用关系最密切的一块

栈在数据结构里是什么意思大家应该知道——先进后出。Java 虚拟机栈也是一样。每个方法被调用的时候,会往栈里压入一个"栈帧"(Stack Frame),方法执行完,栈帧弹出。

一个栈帧里面装的东西包括:

  • 局部变量表:方法里定义的局部变量就放这儿
  • 操作数栈:做运算的时候临时放数据的地方
  • 动态链接:涉及到多态、方法调用时用到的符号引用转直接引用
  • 方法出口:方法执行完了之后返回到哪儿去

我当时学到这里脑子里冒出的第一个问题是:那这个栈到底多大?

答案是不确定。取决于 JVM 的参数设置(-Xss)。但不管设置多大,如果方法调用的层数太深,比如无限递归,栈深度就超过上限了,会抛StackOverflowError

还有一种是栈扩展的时候没成功,抛OutOfMemoryError。这个场景比较少见,一般是线程数量太多导致的。

这也是线程私有的——每个线程有自己的虚拟机栈。


本地方法栈——和上面那个差不多,但不是一回事

Java 虚拟机栈是为 Java 方法服务的。那如果调了一个 native 方法呢?走的不是 Java 的字节码,不能走 Java 虚拟机栈——所以单独搞了一个本地方法栈

不过 HotSpot 虚拟机(就是我们最常用的那个 Oracle JDK 和 OpenJDK 带的虚拟机)里面,本地方法栈和 Java 虚拟机栈合并到一起了。所以实际用的时候感受不到是两个。

同样可能抛StackOverflowErrorOutOfMemoryError


Java 堆——最大的一块,也是 GC 最忙的地方

堆是 JVM 里最大的一块内存。所有的对象实例和数组都在这里分配。

它是线程共享的,JVM 启动的时候就创建好了。

堆里面还被划分成了几个子区域(为了垃圾回收效率优化):

  • 新生代(Young Generation):里面又分三个部分——一个 Eden 区、两个 Survivor 区(S0 和 S1)
  • 老年代(Old Generation / Tenured Generation)

我刚学到这里的时候很不理解:为什么堆还要分这么多区域?后来知道这是为了"分代回收"——大部分对象活不了多久就死了(比如循环里 new 的对象),新生代回收频率高但快;少部分对象命硬,会晋升到老年代,回收频率低。这是一种典型的"二八定律"思路。

堆不够用的时候抛的异常大家都眼熟:OutOfMemoryError: Java heap space


元空间(Metaspace)——取代了方法区的新东西

先说方法区(Method Area)是什么。

方法区是 JVM 规范里的一个逻辑区域,用来存放:

  • 已被虚拟机加载的类信息
  • 常量
  • 静态变量
  • 即时编译器编译后的代码缓存

这个区虽然是堆的逻辑组成部分,但有个别名叫"非堆"(Non-Heap)。所以它虽然是"堆的概念"但不算"堆的实体"。

在 JDK 8 之前,方法区的实现叫永久代(PermGen),在 JVM 堆里面。

到 JDK 8,永久代被干掉了,换成了元空间(Metaspace)。关键的区别是:元空间使用了本地内存,不再是 JVM 堆的一部分了。这意味着它的大小不再受 JVM 堆大小的限制,而是受本机物理内存的限制。

元空间不够用的时候抛OutOfMemoryError: Metaspace


运行时常量池——方法区的一部分

常量池这个词可能你在反编译 class 文件的时候见过。编译器把类里的字面量(比如字符串常量 “hello”、final 常量等)和符号引用(类名、方法名、字段名的引用)放到这个池子里。

运行时常量池就是这些信息在运行时的存放位置,是方法区的一部分。

还有一个特点:动态性。不是只有编译期生成的东西才能放进去。你在代码里调String.intern(),也可以在运行时把字符串扔到常量池里。

内存不够的时候也会抛 OutOfMemoryError。


直接内存——不属于 JVM,但 JVM 可以操作

直接内存是操作系统的本地内存,不归 JVM 管。

那它跟 JVM 有什么关系?Java 里有一个 NIO(New I/O)的 API,可以通过ByteBuffer.allocateDirect()分配一块堆外内存。这块内存的好处是:在进行 I/O 操作(比如读写文件、网络通信)时,数据不用在堆内存和本地内存之间来回拷贝,性能好很多。

很多高性能框架比如Netty就是基于这个原理做优化的。

但是——它是本地内存,所以也受物理内存上限的限制。用得不好也会报OutOfMemoryError: Direct buffer memory


五种内存溢出,一张表总结

学完之后我把五种溢出情况整理了一下:

溢出区域异常信息常见原因
堆溢出Java heap spacenew 大对象、内存泄漏、GC 回收不掉
栈溢出StackOverflowError/OutOfMemoryError递归太深、线程开太多
元空间溢出Metaspace加载类太多、动态类生成、CGLIB 等
直接内存溢出Direct buffer memorydirect buffer 没回收、一直分配

程序计数器那行没写——因为它是唯一不会溢出的。


最后想说的

这些东西我一开始觉得是背概念,背完就忘。后来我发现,真正帮我理解的不是背,而是带着问题去查

  • “为什么栈会溢出?”——因为我写过递归忘记写终止条件
  • “堆溢出是什么时候遇到的?”——因为我导了一个超大 Excel 没分页
  • “元空间溢出在什么场景出现?”——因为看到过用 CGLIB 动态代理搞出来的案例

如果你是新手,我的建议是:不要硬背分区名称。先把以下两个记住就行:

  1. 线程私有的:程序计数器、Java 虚拟机栈、本地方法栈
  2. 线程共享的:堆、元空间(方法区)

剩下的,遇到具体的报错再去翻。等报错见多了,分区图自然就长在脑子里了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/1 10:09:50

Rust的match穷尽性检查与通配符模式在枚举处理中的安全保证

Rust的match穷尽性检查与通配符模式在枚举处理中的安全保证 Rust作为一门注重安全的系统级编程语言,其模式匹配机制通过编译时的穷尽性检查和通配符模式,为枚举处理提供了强大的安全保证。这种设计不仅避免了运行时遗漏分支导致的逻辑错误,还…

作者头像 李华
网站建设 2026/7/1 10:08:43

Sora与可灵AI的“合规临界点”:训练数据来源、生成内容水印、商用授权条款逐条对照(法务+技术双视角·限时公开)

更多请点击: https://kaifayun.com 第一章:Sora与可灵AI的“合规临界点”:训练数据来源、生成内容水印、商用授权条款逐条对照(法务技术双视角限时公开) 当生成式视频模型从实验室走向商业部署,其底层合规…

作者头像 李华
网站建设 2026/7/1 10:07:09

智能合约开发

智能合约开发:区块链世界的自动化契约 在区块链技术蓬勃发展的今天,智能合约作为其核心应用之一,正在重塑金融、供应链、游戏等众多领域的协作方式。智能合约是一种基于代码的自动化协议,能够在满足预设条件时自动执行&#xff0…

作者头像 李华
网站建设 2026/7/1 10:06:06

关于反对屏幕四角贴Tag码辅助定位的情况说明

关于屏幕四角的Tag码01 【屏幕四角Tag码】 卓晴老师:  您好!现就智能视觉赛道中部分队伍通过屏幕四角粘贴Tag码辅助定位的改装行为, 向您反馈相关问题,并说明我方反对该操作的理由。  在智能视觉比赛中,定位精度、畸…

作者头像 李华
网站建设 2026/7/1 10:05:31

5分钟打造个人漫画库:哔咔漫画下载器完整使用指南

5分钟打造个人漫画库:哔咔漫画下载器完整使用指南 【免费下载链接】picacomic-downloader 哔咔漫画 picacomic pica漫画 bika漫画 PicACG 多线程下载器,带图形界面 带收藏夹,已打包exe 下载速度飞快 项目地址: https://gitcode.com/gh_mirr…

作者头像 李华