Java 1.8 虚拟机内存分布详解

createh51周前 (05-16)技术教程3

Java 1.8 虚拟机内存分布详解

Java 1.8 的 JVM 内存布局相比早期版本有显著变化(如永久代被元空间取代)。以下是其核心内存区域的划分、作用及配置参数:


一、JVM 内存整体结构

内存区域

存储内容

配置参数

是否线程私有

堆 (Heap)

对象实例、数组

-Xmx, -Xms

共享

非堆内存

元空间、代码缓存、JVM内部结构

见下文各子区域配置

共享

虚拟机栈

方法调用的栈帧(局部变量、操作数栈、动态链接等)

-Xss

私有

本地方法栈

Native 方法调用的栈帧

同虚拟机栈(部分 JVM 实现合并二者)

私有

程序计数器

当前线程执行的字节码行号指示器

私有


二、堆内存(Heap)

堆是 JVM 中最大且最复杂的内存区域,分为 新生代(Young Generation)老年代(Old Generation)

1. 新生代(Young Generation)

子区域

作用

默认比例

配置参数

Eden 区

新对象分配区域(约 90% 对象在此创建并快速回收)

占新生代的 80%

-XX:SurvivorRatio=8

Survivor0

存放 Minor GC 后存活的对象(用于对象年龄计数)

各占新生代的 10%

(需配合 -Xmn 显式调整)

Survivor1

与 Survivor0 交替使用(复制算法)

同上

同上

新生代配置示例

bash

bash

复制

-Xmn800m                   # 新生代总大小 800MB(Eden 640MB + S0/S1 各 80MB)
-XX:SurvivorRatio=6        # Eden:S0:S1 = 6:1:1(Eden 600MB,S0/S1 各 100MB)

2. 老年代(Old Generation)

特点

触发条件

配置参数

存放长期存活对象(如缓存、连接池)

对象年龄超过阈值(默认15)、大对象直接分配、Survivor 区无法容纳存活对象

-Xmx 和 -Xms 差值决定


三、非堆内存(Non-Heap)

1. 元空间(Metaspace)

特性

与永久代的区别

配置参数

存储类元数据(Class Metadata)

使用本地内存(Native Memory),避免永久代的 OutOfMemoryError

-XX:MetaspaceSize, -XX:MaxMetaspaceSize

默认无上限

可通过 MaxMetaspaceSize 限制

-XX:+UseCompressedClassPointers

元空间配置示例

bash

bash

复制

-XX:MetaspaceSize=256m      # 初始大小(触发 Full GC 的阈值)
-XX:MaxMetaspaceSize=512m   # 最大限制(防止内存泄漏)

2. 代码缓存(Code Cache)

作用

存储内容

配置参数

存储 JIT 编译后的机器码

热点方法编译后的本地代码

-XX:ReservedCodeCacheSize


四、其他关键内存区域

1. 直接内存(Direct Memory)

特性

配置参数

风险

NIO 的 DirectByteBuffer 分配

-XX:MaxDirectMemorySize

未限制可能导致 OOM

2. JVM 自身结构

内存占用

说明

线程栈

每个线程默认占用 1MB(-Xss1m)

GC 算法数据结构

如卡表(Card Table)、标记位图等


五、默认内存分配示例(-Xmx1500m)

text

text

复制

堆内存 (Heap)
├─ 新生代 (Young) : 500MB (默认堆的 1/3)
│  ├─ Eden   : 400MB (SurvivorRatio=8)
│  ├─ S0     : 50MB
│  └─ S1     : 50MB
└─ 老年代 (Old)   : 1000MB

非堆内存 (Non-Heap)
├─ 元空间         : 初始 ~21MB(动态扩展)
├─ 代码缓存       : 默认 240MB
└─ 线程栈         : 每线程 1MB

六、内存监控与调优工具

1. 命令行工具

工具

命令示例

用途

jstat

jstat -gc <pid> 1000

实时监控 GC 和各区内存使用

jmap

jmap -heap <pid>

查看堆内存分配详情

jcmd

jcmd <pid> VM.native_memory

分析 Native Memory 使用

2. 可视化工具

  • VisualVM:监控堆/非堆内存、线程、GC 活动。
  • JConsole:实时查看内存池使用率、类加载情况。

七、调优注意事项

  1. 避免元空间溢出
    即使 -Xmx 足够,未限制 MaxMetaspaceSize 仍可能导致 Native Memory 耗尽。
  2. 合理配置 Survivor 区
    确保 Survivor 区足够容纳每次 Minor GC 的存活对象,防止过早晋升到老年代。
  3. 线程栈内存控制
    高并发应用需降低 -Xss(如 -Xss256k),避免线程数过多导致栈内存耗尽。
  4. 直接内存监控
    使用 -XX:MaxDirectMemorySize 限制 NIO 直接内存分配。

通过理解 Java 1.8 的内存分布,结合显式配置和监控工具,可有效避免内存溢出、GC 频繁等问题,提升应用稳定性。

相关文章

java算法题-在区间范围内统计奇数数目

在leetcode(https://leetcode-cn.com/)上看到一道有趣的算法题:给你两个非负整数 low 和 high 。请你返回 low 和 high 之间(包括二者)奇数的数目。示例...

JVM 深度解析:运行时数据区域、分代回收与垃圾回收机制全攻略

共同学习,有错欢迎指出。JVM 运行时数据区域1. 程序计数器程序计数器是一块较小的内存空间,可看作当前线程所执行的字节码的行号指示器。在虚拟机概念模型里,字节码解释器通过改变这个计数器的值选取下一条...

图解常见的限流算法(计数器、滑动窗口计数、漏桶、令牌桶)

哈喽,大家好呀,我是呼噜噜,好久没有更新文章了,今天我们来聊聊在企业级项目中,常见的几种限流手段的原理及其实现什么场景需要限流随着互联网的业务发展,比如秒杀、双十一、618等这些我们耳熟能详,也有被人...

Java高并发解决方案:轻松应对海量请求

Java高并发解决方案:轻松应对海量请求在当今互联网时代,高并发问题已经成为每个Java开发者绕不开的话题。无论是电商平台的大促活动,还是社交平台的热门话题讨论,都可能瞬间产生海量请求。那么,我们该如...

Java并发工具:CountDownLatch

CountDownLatch是Java并发包(java.util.concurrent)中提供的一种同步工具,用于控制一个或多个线程等待其他线程完成操作。它是一个非常有用的工具类,常用于协调多个线程之...

Java 1.8 堆内存分布详解

Java 1.8 堆内存分布详解Java 1.8 的堆内存(Heap)是 JVM 管理的最大内存区域,用于存储对象实例和数组。其核心分为 新生代(Young Generation) 和 老年代(Old...