本文将介绍以下内容:

  • 对象的创建过程
  • 内存分配分析
  • 内存布局研究

1. 引言

了解.NET的内存管理机制,首先应该从内存分配开始,也就是对象的创建环节。对象的创建,是个复杂的过程,主要包括内存分配和初始化两个环节。例如,对象的创建过程可以表示为:

FileStream fs = new FileStream(@"C:"temp.txt", FileMode.Create);

通过new关键字操作,即完成了对FileStream类型对象的创建过程,这一看似简单的操作背后,却经历着相当复杂的过程和周折。

本篇全文,正是对这一操作背后过程的详细讨论,从中了解.NET的内存分配是如何实现的?

2. 内存分配

关于内存的分配,首先应该了解分配在哪里的问题。CLR管理内存的区域,主要有三块,分别为:

·       线程的堆栈,用于分配值类型实例。堆栈主要由操作系统管理,而不受垃圾收集器的控制,当值类型实例所在方法结束时,其存储单位自动释放。栈的执行效率高,但存储容量有限。

·       GC堆,用于分配小对象实例。如果引用类型对象的实例大小小于85000字节,实例将被分配在GC堆上,当有内存分配或者回收时,垃圾收集器可能会对GC堆进行压缩,详情见后文讲述。

·       LOH(Large Object Heap)堆,用于分配大对象实例。如果引用类型对象的实例大小不小于85000字节时,该实例将被分配到LOH堆上,而LOH堆不会被压缩,而且只在完全GC回收时被回收。

本文讨论的重点是.NET的内存分配机制,因此下文将不加说明的以GC堆上的分配为例来展开。关于值类型和引用类型的论述,请参见[第八回:品味类型---值类型与引用类型(上)-内存有理]。

了解了内存分配的区域,接着我们看看有哪些操作将导致对象创建和内存分配的发生,关于实例创建有多个IL指令解析,主要包括:

·       newobj,用于创建引用类型对象。

·       ldstr,用于创建string类型对象。

·       newarr,用于分配新的数组对象。

·       box,在值类型转换为引用类型对象时,将值类型字段拷贝到托管堆上发生的内存分配。

在上述论述的基础上,下面从堆栈的内存分配和托管堆的内存分配两个方面来分别论述.NET的内存分配机制。

2.1 堆栈的内存分配机制

对于值类型来说,一般创建在线程的堆栈上。但并非所有的值类型都创建在线程的堆栈上,例如作为类的字段时,值类型作为实例成员的一部分也被创建在托管堆上;装箱发生时,值类型字段也会拷贝在托管堆上。

对于分配在堆栈上的局部变量来说,操作系统维护着一个堆栈指针来指向下一个自由空间的地址,并且堆栈的内存地址是由高位到低位向下填充。以下例而言:

        public static void Main()
        {
            int x = 100;
            char c = 'A';
        }

假设线程栈的初始化地址为50000,因此堆栈指针首先指向50000地址空间。代码由入口函数Main开始执行,首先进入作用域的是整型局部变量x,它将在栈上分配4Byte的内存空间,因此堆栈指针向下移动4个字节,则值100将保存在49997~50000单位,而堆栈指针表示的下一个自由空间地址为49996,如图所示:

接着进入下一行代码,将为字符型变量c分配2Byte的内存空间,堆栈指针向下移动2个字节至49994单位,值’A’会保存在49995~49996单位,地址的分配如图:

最后,执行到Main方法的右括号,方法体执行结束,变量x和c的作用域也随之结束,需要删除变量x和c在堆栈内存中的值,其释放过程和分配过程刚好相反:首先删除c的内存,堆栈指针向上递增2个字节,然后删除x的内存,堆栈指针继续向上递增4个字节,程序执行结束,此时的内存状况为:

    其他较复杂的分配过程,可能在作用域和分配大小上有所不同,但是基本过程大同小异。栈上的内存分配,效率较高,但是内存容量不大,同时变量的生存周期随着方法的结束而消亡。

未完待续:托管堆的内存分配机制和必要的补充说明,近期发布,敬请关注。

参考文献

(USA)Joe Duffy, Professinal .NET Framework 2.0

(USA)Don Box, Essiential .NET

(MSDN)Hanu Kommalapati and Tom Christian, Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects, http://msdn.microsoft.com/msdnmag/issues/05/05/JITCompiler/default.aspx

[你必须知道的.NET]第十八回:对象创建始末(上)的更多相关文章

  1. [你必须知道的.NET]第二十八回:说说Name这回事儿

    发布日期:2009.3.18 作者:Anytao © 2009 Anytao.com ,原创作品,转贴请注明作者和出处. 1 缘起 老赵在谈表达式树的缓存(2):由表达式树生成字符串中提到,在描述Ty ...

  2. [你必须知道的.NET]第二十九回:.NET十年(上)

    发布日期:2009.05.08 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...

  3. [你必须知道的.NET]第二十六回:认识元数据和IL(下)

    发布日期:2009.03.04 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回: 第二十四回:认识元数据和IL(上), ...

  4. [你必须知道的.NET]第二十五回:认识元数据和IL(中)

    发布日期:2009.02.25 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回[第二十四回:认识元数据和IL(上)], ...

  5. [你必须知道的.NET]第二十四回:认识元数据和IL(上)

    发布日期:2009.02.24 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 很早就有说说Metadata(元数据)和IL(中 ...

  6. [你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考

    发布日期:2008.8.27 作者:Anytao © 2008 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 走钢丝的人,在刺激中体验快感.带着问题思考,在问题 ...

  7. [你必须知道的.NET]第十九回:对象创建始末(下)

    本文将介绍以下内容: 对象的创建过程 内存分配分析 内存布局研究 接上回[第十八回:对象创建始末(上)],继续对对象创建话题的讨论>>> 2.2 托管堆的内存分配机制 引用类型的实例 ...

  8. [你必须知道的.NET]第二十回:学习方法论

    说在,开篇之前 本文,源自我回答刚毕业朋友关于.NET学习疑惑的回复邮件. 本文,其实早计划在<你必须知道的.NET>写作之初的后记部分,但是因为个中原因未能如愿,算是补上本书的遗憾之一. ...

  9. [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望

    发布日期:2009.05.22 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文开始,将以& ...

随机推荐

  1. 解题:NOIP 2018 赛道修建

    题面 几乎把我送退役的一道题,留在这里做个纪念. 考场看出来是原题结果为了求稳强行花了一个小时写了80pts暴力,然后挂了55pts(真·暴力写挂),结果今天花了不到半个小时连想带写一遍95pts(T ...

  2. C++ ------ static_cast,dynamic_cast,reinterpret_cast,const_cast

    C++类型转换分为:隐式类型转换和显式类型转换 第1部分. 隐式类型转换 又称为“标准转换”,包括以下几种情况:1) 算术转换(Arithmetic conversion) : 在混合类型的算术表达式 ...

  3. Codeforces 620C EDU C.Pearls in a Row ( set + greed )

    C. Pearls in a Row There are n pearls in a row. Let's enumerate them with integers from 1 to n from ...

  4. JavaScript入门笔记(一)

    JavaScipt 2.1 javascript的组成部分 ECMAScript: 它是整个 javascript 的核心,包含(基本语法.变量.关键字.保留字.数据类型.语句.函数等等)DOM:文档 ...

  5. Ubuntu 14.04 安装Visual studio Code

    上一篇简单介绍了Ubuntu 14.04上如何创建.运行 hello world 程序. 这篇介绍Ubuntu 14.04如何安装Visual studio Code. 网上推荐的有通过Ubuntu ...

  6. CSS实现箭头效果

    有时候网页中使用箭头以增强效果,一般的做法是使用图片,今天我们使用CSSCSS来实现“箭头效果”,使用CSS我们必须兼容所有浏览器(IE6.7.8.9.10.+),Chrome,Firefox,Ope ...

  7. 【swupdate文档 五】从可信的来源更新镜像

    从可信的来源更新镜像 现在越来越重要的是,设备不仅要能安全地进行更新操作, 而且要能够验证发送的图像是否来自一个已知的源, 并且没有嵌入恶意软件. 为了实现这个目标,SWUpdate必须验证传入的镜像 ...

  8. python基础===map, reduce, filter的用法

    filter的用法: 这还是一个操作表list的内嵌函数'filter' 需要一个函数与一个list它用这个函数来决定哪个项应该被放入过滤结果队列中遍历list中的每一个值,输入到这个函数中如果这个函 ...

  9. kvm命令参数记录

    /usr/libexec/qemu-kvm -cpu host -m 1024 -enable-kvm -drive file=/var/lib/libvirt/images/zxc_linux1.i ...

  10. 关于DataTable.Select不到数据的一种解决方案

    网上有很多说的,试过,都没用.自己研究了一下,解决方案如下: 建立dataview,用dv.rowfilter,就可以取到了,然后TOTABLE即可. 代码如下:(只看中间那几句即可) private ...