当前位置: 首页 > news >正文

用最简单的解释告诉你C#中堆栈和内存的关系

在学习C#的过程中,很多初学者会被“堆栈”“内存”这些概念绕晕,甚至误以为“堆栈”是独立于内存之外的东西。其实答案很简单:内存是程序运行时的“整块储物空间”,而堆栈(栈+堆)只是这块大空间里划分出的两个功能不同的“小区域”。就像家里的大衣柜,栈是随手放钥匙、手机的抽屉,堆是挂大衣、放被子的挂区,两者分工明确,配合起来才能让“衣物收纳”(程序运行)顺畅高效。

先搞懂:内存里的“快速抽屉”——栈(Stack)

栈是内存中专门负责“快速存取临时数据”的区域,就像衣柜里的小抽屉,只能放小件、常用的物品,而且取放规则很固定:“先进后出”(先放进去的东西要最后才能拿出来)。

在C#程序里,栈主要存放这些东西:方法里的局部变量、函数的参数、程序运行的临时状态等。比如以下代码中,int age局部变量、string name局部变量,还有CalculateSum方法的ab参数,都会存在栈里:

// 示例代码片段 static void Main() { int age = 25; // 局部变量,存栈中 string name = "张三"; // 引用存栈中,字符串对象存堆中 int sum = CalculateSum(10, 20); // 10、20参数存栈中 } static int CalculateSum(int a, int b) // a、b参数存栈中 { return a + b; }

栈的特点特别好记:一是存取速度极快,程序会自动帮你“放”和“收”——方法执行开始时,局部变量自动进栈;方法执行结束后,栈里的这些变量会被自动清理,根本不用你手动管理;二是空间有限,就像小抽屉装不下大件物品,要是局部变量太多、嵌套调用方法层数太深,还可能出现“栈溢出”的错误。

再明白:内存里的“大容量挂区”——堆(Heap)

堆是内存中负责“存放长期、大容量数据”的区域,对应衣柜的挂区,能放体积大、需要长期使用的物品,而且没有“先进后出”的限制,想放哪里、取哪里都可以。

C#里那些“用new关键字创建的对象”,都存在堆里。比如以下代码中new Person()创建的Person对象本身、Person类的Name属性对应的后台字段,都躺在堆里。除此之外,字符串、数组等需要动态分配空间的数据,也会存在堆里:

// 示例代码片段 class Person { public string Name { get; set; } // 属性后台字段存堆中 } static void Main() { Person person = new Person(); // new创建的对象存堆中 person.Name = "李四"; // 字符串对象"李四"存堆中 int[] scores = new int[3] { 90, 85, 95 }; // 数组对象存堆中 }

堆的特点和栈正好互补:一是空间大,能存放栈放不下的“大件数据”;二是不会自动清理——堆里的对象创建后,会一直存在,直到C#的“垃圾回收器”(GC)发现它没人用了,才会过来清理;三是存取速度比栈慢,因为堆里的数据没有固定顺序,程序需要先找到数据的“地址”才能访问。

关键配合:栈里存“地址”,堆里存“实物”

很多人困惑的点在于:栈和堆不是孤立的,而是靠“地址引用”配合工作的。我们用一段完整的核心代码举例,一看就懂:

class Student { public int Score { get; set; } // 属性后台字段存堆中 } static void Main() { Student stu = new Student(); // 关键代码:栈与堆配合 stu.Score = 98; // 赋值操作的栈堆协同 }

这行代码执行时,会发生两件事:

1. 等号左边的stu变量(这是一个“引用”),会被存到里——它就像一张“地址纸条”,只记录着堆里Student对象的位置,本身很小;

2. 等号右边的new Student()创建的Student对象(包括它的Score属性、对应的后台字段),会被存到里——这是真正的“实物”,占用的空间比栈里的“地址纸条”大得多。

后续写stu.Score = 98;赋值时,程序会先从栈里找到stu这张“地址纸条”,跟着地址找到堆里的Student对象,再修改它的Score字段;如果后续写int studentScore = stu.Score;,程序也是先通过栈里的地址找到堆里的对象,再把Score的值取出来,存到栈里的studentScore变量中。

总结:记住3句话,再也不混淆

1. 内存是“大整体”,堆栈是内存里的“两个功能区”,不是独立存在的;

2. 栈放“小而临时”的东西(局部变量、参数、引用地址),自动清理、速度快;

3. 堆放“大而长期”的东西(new出来的对象、数组),需要GC清理、靠栈里的地址访问。

理解了这个关系,再看C#属性访问器对应的IL代码(比如自动属性的get、set访问器)就会更清晰:IL指令里的ldarg.0(取当前对象的引用,存于栈中)、ldfld(根据地址去堆里取字段),本质上就是在协调栈和堆的配合工作。

http://www.cnnetsun.cn/news/103774.html

相关文章:

  • Ant Design Vue Pro Components:打造企业级Vue3应用的全新体验
  • 如何彻底解决Dify代码执行难题?终极实战方案揭秘
  • ESP32 买谁家的?首选 — 深圳四博智联!
  • Argos Translate终极指南:离线多语言翻译完整教程
  • NetBox拓扑视图插件:网络架构可视化的终极解决方案
  • 深度剖析FT Transformer模型一致性挑战与实战解决方案
  • 9、基于 GEE 的区域蒸散发时序分析与动态评估系统
  • AI绘图自动化工具集:释放创意潜能的终极解决方案
  • 6、Teradata SQL 数据定义与索引使用全解析
  • Arduino CAN总线开发完整指南:从入门到实战
  • kali linux常用网络安全监控工具篇——Burp Suite,黑客/网安新手必看系列!
  • EmotiVoice语音合成情感记忆功能:记住用户偏好发音风格
  • 专业图表绘制神器:drawio-libs图标库深度使用指南
  • Vue3 TypeScript管理模板:企业级后台系统终极解决方案
  • 30、构建自定义 Oracle 插件及 Nagios 配置参数详解
  • 14、网络监控利器:NRPE与SNMP深度解析
  • 【每日算法】LeetCode 20. 有效的括号
  • Photoshop图层批量导出终极指南:10倍效率提升的完整教程
  • 【每日算法】LeetCode 739. 每日温度:从暴力遍历到单调栈的优雅解决
  • Golin终极指南:网络安全扫描与等保核查的完整解决方案
  • 77、由于您仅提供了“以下”两个字,没有具体的英文内容,所以我无法按照要求为您生成博客,请您提供完整的英文内容。
  • Grafana中文版终极指南:快速搭建专业数据可视化监控平台
  • 4、Mac OS X系统使用指南:从Launchd到Shell操作
  • 6、Mac OS X 文件操作全攻略
  • XXPermissions深度解析:Android权限框架的架构揭秘与实践指南
  • PDF翻译格式错乱终极解决方案:三步实现完美排版修复
  • 41、深入了解 IPv6:从基础到实践
  • 47、搭建 Linux 拨号服务器与网络故障排查全攻略
  • 3步轻松掌控电脑风扇:FanControl免费调校完整教程
  • 49、网络故障排查工具大全及使用指南