[译].Net中的内存
原文链接:https://jonskeet.uk/csharp/memory.html
人们在理解值类型和引用类型之间的差异时因为“值类型在栈上分配,引用类型在堆上分配”这句话造成了很多混乱。这完全是不对的,本文试图澄清这个问题。
变量中有什么?
理解.NET中内存工作方式的关键是理解变量是什么,以及它的值是什么。在最基本的层面上,变量是变量名和内存之间的关联。变量的值是与之关联的内存中的内容。该值占用内存空间的大小和值的解释取决于变量的类型 - 这正是值类型和引用类型之间的差异所在。
引用类型变量的值始终是引用或null
。如果是引用,则它必须是与其变量类型兼容的对象的引用。例如,以Stream s声明的变量s的值是null或Stream类型(或其兼容类型)实例的引用。引用类型变量所占内存空间的大小是引用的大小,引用的大小在32位模式下固定为4个字节,在64位模式下固定为8个字节。
值类型变量的值始终是其对象本身的值。例如,对于给定的结构:
struct PairOfInts
{
public int a;
public int b;
}
以PairOfInts pair声明的变量pair的值是整数对本身,而不是对一对整数的引用。其所占内存空间则是两个整数的大小,即8个字节。请注意,值类型变量永远不能赋值为null - 因为这没有任何意义,值类型变量不是一个引用。
那么东西存放在哪里?
变量的分配位置取决于声明它的上下文:
- 局部变量在栈上分配。这包括引用类型变量 - 变量本身位于栈上,其引用的值分配在堆上。方法参数也计为局部变量,但如果使用ref、out、in修饰符修饰它们,则它们不再是原始类型,而是转换为托管指针类型(Type &),此时传递的是原变量的指针,不再是变量本身。
- 引用类型的对象始终在堆上分配。
- 值类型的对象始终内联分配。即在方法中声明的值类型变量在栈上分配,而作为类的实例字段的值类型变量将在堆上分配。
- 静态变量在堆上分配,包括引用类型和值类型中声明的静态变量。无论创建多少个实例,静态变量都共享一个内存空间。
上述规则有几个例外:在使用匿名方法时的外部变量和迭代器中的局部变量会由编译器优化为其它类型的实例字段,这些变量会转移到堆中分配。
举个例子
上述文字描述可能听起来有点复杂,但一个完整的例子可以让事情更清楚一些:
using System; struct PairOfInts
{
static int counter = ; public int a;
public int b; internal PairOfInts(int x, int y)
{
A = x;
B = y;
counter++;
}
} class Test
{
PairOfInts pair;
string name; Test(PairOfInts p, string s, int x)
{
pair = p;
name = s;
pair.a + = x;
} static void Main()
{
PairOfInts z = new PairOfInts(, );
Test t1 = new Test(z, "first", );
Test t2 = new Test(z, "second", );
Test t3 = null;
Test t4 = t1;
//XXX
}
}
让我们看一下标记“XXX”位置时内存中的内容。
- 在栈上分配一个PairOfInts类型的对象,对应变量z。
- 在堆上分配一个Test类型的对象,在栈上分配一个引用指向该对象,对应变量t1。以32位模式举例,该对象在堆中占用20个字节:8个字节的头信息(所有堆对象都有),8个字节用于存储PairOfInts实例,4个字节用于存储字符串引用。
- 在堆上分配一个Test类型的对象,在栈上分配一个引用指向该对象,对应变量t2。该对象与上面的对象非常相似。
- 在栈上分配一个引用,对应变量t3。这个引用是null - 它没有引用任何对象。
- 在栈上分配一个引用,对应变量t4,并赋值t1引用的对象,此时t1和t4引用堆内存中的同一个对象。
- 最后,在堆内存中有一个静态变量PairOfInts.counter。
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!
作者:Minotauros
出处:https://www.cnblogs.com/minotauros/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
[译].Net中的内存的更多相关文章
- Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式
Linux就这个范儿 第15章 七种武器 linux 同步IO: sync.fsync与fdatasync Linux中的内存大页面huge page/large page David Cut ...
- c++继承中的内存布局
今天在网上看到了一篇写得非常好的文章,是有关c++类继承内存布局的.看了之后获益良多,现在转在我自己的博客里面,作为以后复习之用. ——谈VC++对象模型(美)简.格雷程化 译 译者前言 一个C ...
- C++继承 派生类中的内存布局(单继承、多继承、虚拟继承)
今天在网上看到了一篇写得非常好的文章,是有关c++类继承内存布局的.看了之后获益良多,现在转在我自己的博客里面,作为以后复习之用. ——谈VC++对象模型(美)简.格雷程化 译 译者前言 一个C ...
- 如何使用 DBCC MEMORYSTATUS 命令来监视 SQL Server 2005 中的内存使用情况
https://technet.microsoft.com/en-us/solutionaccelerators/dd537566.aspx 注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完 ...
- 浅入 .NET Core 中的内存和GC知识
目录 托管代码 自动内存管理 参考资料: [1]https://docs.microsoft.com/zh-cn/dotnet/standard/managed-code [2]:https://do ...
- Java中堆内存和栈内存详解2
Java中堆内存和栈内存详解 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...
- Unity游戏开发中的内存管理_资料
内存是手游的硬伤——Unity游戏Mono内存管理及泄漏http://wetest.qq.com/lab/view/135.html 深入浅出再谈Unity内存泄漏http://wetest.qq.c ...
- Java中堆内存和栈内存详解
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- C++中的内存管理
在C++中也是少不了对内存的管理,在C++中只要有new的地方,在写代码的时候都要想着delete. new分配的时堆内存,在函数结束的时候不会自动释放,如果不delete我分配的堆内存,则会造成内存 ...
随机推荐
- ADMethodsAccountManagement 一些简单注释添加
using System; using System.Collections; using System.Text; using System.DirectoryServices.AccountMan ...
- 统计插件,Highcharts,以及modelformset
一.modelfromset组件 1.作用:用于批量处理多个表单 form表单对应的组件是formset Modelform对应的组件是modelformset 2.引入 From django.fo ...
- Java入门网络编程-使用UDP通信
程序说明: 以下代码,利用java的网络编程,使用UDP通信作为通信协议,描述了一个简易的多人聊天程序,此程序可以使用公网或者是局域网进行聊天,要求有一台服务器.程序一共分为2个包,第一个包:udp, ...
- python文件及路径管理函数
glob模块 说明: 1.glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,就类似于Windows下的文件搜索, 支持通配符操作 *.?.[] 这三个通配符,*代表0 ...
- 【设计模式】行为型09访问者模式(Visitor Pattern)
学习地址:https://blog.csdn.net/u012124438/article/details/70537203(参考了很多博客,只有这个讲明白了核心点) 访问者模式(Visitor P ...
- mvc中的表现和数据分离怎么理解?
使用过 JavaScript框架(如 AngularJS, Backbone)的人都很熟悉在UI(用户界面,前端)中mvc的工作机理.这些框架实现了MVC,使得在一个单页面中实现根据需要变化视图时更加 ...
- 使用pymysql操作mysql数据库
PyMySQL的安装和连接 PyMySQL的安装 python3. -m pip install pymysql python连接数据库 import pymysql # 创建连接 conn = py ...
- SpringMVC_Two
SpringMVC_Two 响应数据和结果视图 创建工厂 导坐标: </load-on-startup> </servlet> <servlet-mapping> ...
- 基于SpringBoot从零构建博客网站 - 开发设置主页标识和修改个人信息功能
由于守望博客系统中支持由用户自己设置个人主页的URL的后半段,所以必须要用户设置该标识的功能,而且是用户注册登录之后自动弹出的页面,如果用户没有设置该标识,其它的操作是不能够操作的,同时要求主页标识只 ...
- mysql远程连接设置
mysql远程连接设置只需要把mysql数据库的user表中的localhost改成%就可以远程连接了. 值得提醒的是:开发阶段可以打开,生产的时候尽量关闭,因为本人就遇到别人通过这个把我数据库给删的 ...