C# 内存机制详解:值类型、引用类型与 String 的不可变性


C# 内存机制详解:值类型、引用类型与 String 的不可变性

1. 值类型 (Value Type)

代表类型: int, bool, struct, double, char 等。

特点

  • 存储位置: 变量名和实际数据都保存在 栈 (Stack) 中。
  • 赋值行为: 直接拷贝一份完整的数据。修改其中一个,另一个不受影响。

代码示例

csharp 复制代码
int a = 10;
int b = a; // 拷贝具体的值
b = 20;    // 修改 b,a 依然是 10

内存图解

text 复制代码
栈 (Stack)                 堆 (Heap)
+----------+----------+   +-------------------+
| 变量名    |   数据   |   |                   |
+----------+----------+   |                   |
|    a     |    10    |   |  (值类型不占用堆)   |
+----------+----------+   |                   |
|    b     |    20    |   |                   |
+----------+----------+   +-------------------+

2. 引用类型 (Reference Type)

代表类型: class, interface, array, delegate 等。

特点

  • 存储位置: 栈中存的是 内存地址 (指针) ,实际的对象内容存在 堆 (Heap) 中。
  • 赋值行为: 拷贝的是地址。两个变量指向同一个堆对象。

代码示例

csharp 复制代码
Person p1 = new Person { Name = "Alice" };
Person p2 = p1;  // 拷贝地址,两人指向同一个对象
p2.Name = "Bob"; // 通过 p2 修改堆内容,p1.Name 也会变成 "Bob"

内存图解

text 复制代码
栈 (Stack)                          堆 (Heap)
+----------+-----------+           +--------------------------+
| 变量名    |  内存地址  |           |        对象实际数据        |
+----------+-----------+           +--------------------------+
|   p1     |  [0x001]  | --------> | 地址[0x001]: {Name:"Bob"} |
+----------+-----------+      /    +--------------------------+
|   p2     |  [0x001]  | ----/     (p1和p2共享同一块堆空间)
+----------+-----------+

3. String 的特殊性:不可变的引用类型

string 是引用类型,但在行为上表现得像值类型,这就是因为它的 不可变性 (Immutability)。

核心规则

一旦在堆上创建了字符串对象,它的内容就永远不能被修改。 所有的"修改"操作实际上都是在堆中创建了一个全新的字符串对象,并让变量指向新地址。

代码演示与内存步解

csharp 复制代码
string s1 = "Hi";
string s2 = s1; // s2 指向与 s1 相同的地址
s2 = "Yo";      // 并不是修改 "Hi",而是新开辟空间存 "Yo"
第一步:执行 s1 = "Hi"; s2 = s1;
text 复制代码
栈 (Stack)                          堆 (Heap)
+----------+-----------+           +---------------------+
| 变量名    |  内存地址  |           |      字符串对象      |
+----------+-----------+           +---------------------+
|   s1     |  [0xAAA]  | --------> | [0xAAA]: "Hi"       |
+----------+-----------+      /    +---------------------+
|   s2     |  [0xAAA]  | ----/
+----------+-----------+
第二步:执行 s2 = "Yo";
text 复制代码
栈 (Stack)                          堆 (Heap)
+----------+-----------+           +---------------------+
| 变量名    |  内存地址  |           |      字符串对象      |
+----------+-----------+           +---------------------+
|   s1     |  [0xAAA]  | --------> | [0xAAA]: "Hi"       |
+----------+-----------+           +---------------------+
|   s2     |  [0xBBB]  | --------> | [0xBBB]: "Yo"       |
+----------+-----------+           +---------------------+

4. 总结对比表

特性 值类型 (Value Type) 引用类型 (Reference Type) String (特殊引用类型)
存储位置 栈 (Stack) 栈(地址) + 堆(对象) 栈(地址) + 堆(对象)
赋值行为 拷贝具体数值 拷贝内存地址 拷贝内存地址
修改行为 原地修改变量值 原地修改堆中的对象内容 禁止原地修改,创建新对象并更向新地址
典型代表 int, struct class, array string

为什么 String 要这样设计?

  1. 性能与内存: 支持"字符串驻留",相同内容的字符串在内存中只存一份。
  2. 安全: 字符串作为参数传递(如文件路径)时,不会在途中被意外修改。
  3. 线程安全: 多个线程同时读一个不可变对象,不需要加锁。

提示:在进行大量字符串拼接操作时,请务必使用 StringBuilder 以避免在堆中产生大量无用的中间字符串碎片。

相关推荐
EatFan2 小时前
Spring Boot 4 落地观察:从 yudao-cloud、matecloud、JPower 看国产脚手架的升级路线与迁移清单
java·spring boot·后端·spring cloud·微服务·后端开发·jdk 21
Maiko Star2 小时前
* LangChain 提示词模板详解:ChatPromptTemplate 的使用与高级特性
java·人工智能·langchain
波力海苔夹心脆6753 小时前
C# 序列化与反序列化详解:System.Text.Json、Newtonsoft.Json、XmlSerializer 用法、特性选项与安全实践
经验分享·后端·c#·json·.net
现任明教教主~4 小时前
Thinkphp站群蜘蛛池SaaS系统YanyvSEO含多用户/积分/六大引擎计费/易支付对接
java·开发语言·spring
一条破秋裤5 小时前
Linux 线程创建:pthread_create 与基本回收
java·linux·运维
布吉岛的石头5 小时前
Java 程序员第 49 阶段5:BERT 预训练目标 MLM+NSP 的工程含义
java·人工智能·深度学习·bert·transformer
摇滚侠6 小时前
《On Java 中文版 基础卷》阅读笔记 对象无处不在 03
java·笔记·python
二十雨辰6 小时前
[学成在线]-01项目背景
java
弈栈录7 小时前
Java AI 应用的异步化与高并发设计
java·后端·架构
落魄实习生7 小时前
Agent Scope Java 2.x 系列【2】 ReActAgent
java·开发语言