
在 Java 中十万个长度为 "beijing_123132" 的字符串是多少 M?
<!-- more -->
- [三个长度单元](#%E4%B8%89%E4%B8%AA%E9%95%BF%E5%BA%A6%E5%8D%95%E5%85%83)
- [字符 character 维度](#%E5%AD%97%E7%AC%A6%20character%20%E7%BB%B4%E5%BA%A6)
- [字节 Byte 维度](#%E5%AD%97%E8%8A%82%20Byte%20%E7%BB%B4%E5%BA%A6)
- [KB,MB](#KB%EF%BC%8CMB)
- [位数 Bit 维度](#%E4%BD%8D%E6%95%B0%20Bit%20%E7%BB%B4%E5%BA%A6)
- [案例分析](#%E6%A1%88%E4%BE%8B%E5%88%86%E6%9E%90)
- [普通情况](#%E6%99%AE%E9%80%9A%E6%83%85%E5%86%B5)
- [JVM 中](#JVM%20%E4%B8%AD)
- [字符串存储分析](#%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%AD%98%E5%82%A8%E5%88%86%E6%9E%90)
- [JVM 中两百万个字符串的总内存占用](#JVM%20%E4%B8%AD%E4%B8%A4%E7%99%BE%E4%B8%87%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%80%BB%E5%86%85%E5%AD%98%E5%8D%A0%E7%94%A8)
- [注意](#%E6%B3%A8%E6%84%8F)
## 三个长度单元
### 字符 character 维度
字符不分中西!比如,字符串 " 我爱 b" 由三个字符组成:两个中文字符 " 我 " 和 " 爱 ",以及一个英文字符 "b"。总计,这个字符串是由三个字符构成的。在编码中,字符的数量是指字符串中的元素总数,不论这些字符是属于*哪种语言或符号系统*。
### 字节 Byte 维度
| 类型 | 字符示例 | ASCII 字节数 | UTF-8 字节数 | UTF-16 字节数 |
|------|---------|-----------|-----------|------------|
| 英文字符 | A, z, 1 | 1 字节 | *1 字节* | 2 字节 |
| 中文字符 | 中, 文 | 不适用 | *3 字节* | 2 字节 |
| 特殊符号 | @, #, $ | 1 字节 | 1 字节 | 2 字节 |
| 特殊符号 | €, ©, ¼ | 不适用 | 2-3 字节 | 2 字节 |
| 表情符号 | 😊, 🚀 | 不适用 | 4 字节 | 4 字节 |
UTF-8 里一个中文字符需要 3 字节,Java 里一个 char 是 2byte,如果用 UTF-8 岂不是就不够了,所以其实 Java 用的是 UTF-16
### KB,MB
知道字节就可以算我们常说的 KB 和 MB 了
1. **1 Kilobyte (KB)**:
- **在二进制计数系统中**,1 KB 等于 210210 字节,也就是 1024 字节。
- 因此,1 KB 等于 1024×8=81921024×8=8192 bits。
2. **1 Megabyte (MB)**:
- **在二进制计数系统中**,1 MB 等于 220220 字节,也就是 1,048,576 字节。
- 因此,1 MB 等于 1,048,576×8=8,388,6081,048,576×8=8,388,608 bits。
### 位数 Bit 维度
1 byte = 8 bits
不管啥字符集,1 byte = 8 bits,代表 256 种变换,所以表示英文绰绰有余
UTF-16 里, 2 byte = 16 bits,代表 6w 种变换,表示中文也绰绰有余了
UTF-8 里, 3 byte = 24 bits,代表 1600w 种变换,表示中文 更富裕了
## 案例分析
> "beijing_11352" 是多少字符,多少 byte,多少 bit?多少 KB?多少 MB?
### 普通情况
200w(个数)* 12(字符数)* 2(由字符集决定)= 40000000 byte = 40MB
### JVM 中
在 Java 虚拟机(JVM)中处理两百万个 "beijing_11352" 字符串的内存占用,还需要考虑到 JVM 对字符串的特殊处理和管理。这包括字符串对象的开销、字符串池的可能影响(如果字符串被内部化),以及字符数组本身的存储开销。
#### 字符串存储分析
1. **基本存储**:
- 一个 "beijing_11352" 字符串由 12 个字符组成,使用 UTF-16 编码(Java 的默认字符编码)。在 UTF-16 中,大多数字符(包括所有基本多语言平面(BMP)的字符)占用 2 个字节。因此,每个字符串的字符数组需要 12×2=2412×2=24 bytes。
2. **字符串对象的开销**:
- 每个 Java 对象都有一个对象头。在大多数 64 位 JVM 上,对象头通常占用 12 bytes。另外,对于数组对象,还需要额外的空间来存储长度信息,通常是 4 bytes。
- 因此,每个字符串对象的总开销包括对象头和字符数组的开销:12+4+24=4012+4+24=40 bytes。
#### JVM 中两百万个字符串的总内存占用
1. **总内存开销**:
- 如果没有字符串内部化或优化(比如字符串去重),每个字符串的存储开销为 40 bytes,两百万个字符串则需要:40 bytes×2,000,000=80,000,000 bytes40bytes×2,000,000=80,000,000bytes
2. **转换为 KB 和 MB**:
- 80,000,000 bytes1024≈78,125 KB102480,000,000bytes≈78,125KB
- 80,000,000 bytes1024×1024≈76.294 MB1024×102480,000,000bytes≈76.294MB
#### 注意
- **字符串池**:在 Java 中,字符串字面量自动被内部化,存储在 JVM 的字符串池中。如果这些字符串是动态生成的并且不被显式地内部化(使用 `String.intern()`),则每个字符串都将占用独立的内存空间。如果使用字符串字面量或已内部化的字符串,那么内存占用可能会减少,因为多个字符串引用将指向内存中的同一对象。
- **压缩指针**:在较新的 JVM 实现中,如果堆大小小于 32GB,通常可以使用压缩指针,这可能减少对象引用所需的空间,从而略微降低每个字符串对象的内存占用。
总结来说,两百万个 "beijing_11352" 字符串在没有特别优化的情况下,大约需要 76.294 MB 的内存,这考虑了每个字符串实例和字符数组的存储需求。
- [ ] java 中的字符串为什么从 char 数组换成了 byte 数组 ⏰ 2024-04-30 📅 2024-04-30