这是一个非常经典的问题,但它的答案取决于你问的是哪个“Java String”,我会从三个层面来详细解释:

从“类”的角度看:java.lang.String 类本身有多大?
如果你问的是 String 这个类对象在内存中占用多少字节,答案是:它的大小是固定的,通常是 16 字节(在 64 位 JVM 中,开启压缩指针的情况下)。
这 16 字节由以下部分组成(以常见的 HotSpot JVM 为例):
| 部分 | 大小 (字节) | 描述 |
|---|---|---|
| Mark Word | 8 | 对象的“标记”,用于存储哈希码、锁状态、分代年龄等,这是所有 Java 对象都有的部分。 |
| Klass Pointer | 4 (或 8) | 指向该对象所属的类元数据的指针,在 64 位 JVM 且开启 UseCompressedClassPointers (默认开启) 时为 4 字节,否则为 8 字节。 |
| 长度 (length) | 4 | 一个 int 值,存储字符串的字符数量。 |
| 对齐填充 (Padding) | 4 | 为了让对象的总大小是 8 字节的倍数(64 位系统上对象内存按 8 字节对齐),需要填充 4 字节。 |
| 总计 | 16 |
关键点:
String对象本身不存储字符数据!它只存储字符的数量和指向字符数组的指针。- 字符数据("你好" 这两个汉字)存储在另一个叫做
char[]的数组对象中。
从“实例”的角度看:一个具体的字符串变量占多少内存?
这取决于字符串的内容长度,内存消耗分为两部分:

a) String 对象本身 (固定部分)
如上所述,通常是 16 字节。
b) 底层的 char[] 数组对象 (可变部分)
这个数组对象的大小也由固定部分和可变部分组成。
| 部分 | 大小 (字节) | 描述 |
|---|---|---|
| Mark Word | 8 | 数组对象的标记。 |
| Klass Pointer | 4 | 指向 char[] 类型的指针。 |
| 长度 (length) | 4 | 一个 int 值,存储数组的长度。 |
| 数据区 (Data) | 字符数 * 2 |
每个字符在 Java 中是 2 字节的 UTF-16 编码。 |
| 对齐填充 (Padding) | 0 | (如果总大小刚好是 8 的倍数则不需要) |
| 总计 | *16 + 字符数 2** |
一个完整的字符串实例的总内存占用 ≈ String对象大小 + char[]数组对象大小
总大小 ≈ 16 + (16 + 字符数 2) = 32 + 字符数 2
举例说明
假设我们有以下 Java 代码:
String str = "你好"; // 两个汉字
我们来计算 str 这个变量在内存中占用的总空间:
-
String对象部分 (固定)Mark Word: 8 字节Klass Pointer: 4 字节length: 4 字节 (值为 2)Padding: 4 字节- 小计: 16 字节
-
char[]数组对象部分 (可变)Mark Word: 8 字节Klass Pointer: 4 字节length: 4 字节 (值为 2)- 数据区:
2 个字符 * 2 字节/字符 = 4 字节 - 小计: 8 + 4 + 4 + 4 = 20 字节
-
总计
String对象 +char[]数组对象 = 16 + 20 = 36 字节
变量 str "你好" 在内存中总共占用了 36 字节。
从“字符串字面量”的角度看:"abc" 有几个字?
如果你问的是 String 字面量(代码中直接写的字符串),"abc",
- "abc" 这三个字符本身:每个字符在 Java 中是 2 字节,
3 * 2 = 6字节。 String对象:如上所述,它包含一个指向字符数组的指针和长度信息,对象本身固定为 16 字节(在 64 位 JVM 中)。
重要知识点:字符串常量池
Java 为了优化性能和内存,有一个叫做字符串常量池 的区域,当你写 "abc" 时,JVM 会在编译期或类加载时,在常量池中创建一个 String 对象,如果代码中其他地方也出现了 "abc",它们都会引用常量池中同一个对象,而不会重复创建。
String s1 = "abc"; 和 String s2 = "abc"; 中,s1 和 s2 指向的是内存中同一个 String 对象。
| 问题 | 答案 | 解释 |
|---|---|---|
String 类本身有多大? |
16 字节 (64位JVM, 压缩指针) | 这是 String 对象头和 length 字段的总和,不包含字符数据。 |
| 一个字符串变量占多少内存? | *32 + (字符数 2) 字节** | 由 String 对象 (16字节) 和 char[] 数组对象 (16 + 字符数*2 字节) 组成。 |
"你好" 占多少内存? |
36 字节 | String对象(16) + char[]数组(20) = 36 字节。 |
"abc" 这几个字? |
字符部分 6 字节 | 字符 'a', 'b', 'c' 每个占 2 字节,但完整的 String 对象占更多内存。 |
如何准确测量? 如果你想精确测量一个字符串占用的内存,不要自己计算,使用专业的工具:
- JOL (Java Object Layout): 轻量级,可以打印出对象的内存布局。
- VisualVM / JProfiler / YourKit: 功能强大的性能分析工具,可以查看堆内存中对象的大小和数量。
