C#中值类型和引用类型

http://www.cnblogs.com/123clb/archive/2011/03/03/1969712.html

概念:

1.值类型:数据存储在内存的堆栈中,从堆栈中可以快速地访问这些数据,因此,值类型表示实际的数据。

2.引用类型:表示指向存储在内存堆中的数据的指针或引用(包括类、接口、数组和字符串)。

C#中定义的值类型包括原类型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚举(enum)、结构(struct)

引用类型包括:类、数组、接口、委托、字符串等。

区别:

基本区别在于它们在内存中的存储方式。值类型只将值存放在内存中,这些值类型都存储在堆栈中。原始数据类型(如bool和int)都属于此类型。而引用类型的内存单元中只存放内存堆中对象的地址,而对象本身放在内存堆中。如果引用的值类型的值是null,则表示未引用任何对象。

堆和堆栈区别:

堆和堆栈是两个不同的概念,在内存中的存储位置也不相同,

堆一般用于存储可变长度的数据,如字符串类型;

堆栈则用于存储固定长度的数据,如整型类型的数据int(每个int变量占用四个字节)。由数据存储的位置可以得知,当把一个值变量赋给另一个值变量时,会在堆栈中保存两个完全相同的值;而把一个引用变量赋给另一个引用变量,则会在堆栈中保存对同一个堆位置的两个引用,即在堆栈中保存的是同一个堆的地址。在进行数据操作时,对于值类型,由于每个变量都有自己的值,因此对一个变量的操作不会影响到其它变量;对于引用类型的变量,对一个变量的数据进行操作就是对这个变量在堆中的数据进行操作,如果两个引用类型的变量引用同一个对象,实际含义就是它们在堆栈中保存的堆的地址相同,因此对一个变量的操作就会影响到引用同一个对象的另一个变量。

为了更好地说明两种类型之间的区别,借用如下的表格来说明。

  值类型 引用类型
内存分配地点 分配在栈中 分配在堆中
效率 效率高,不需要地址转换 效率低,需要进行地址转换
内存回收 使用完后,立即回收 使用完后,不是立即回收,等待GC回收
赋值操作 进行复制,创建一个同值新对象 只是对原有对象的引用
函数参数与返回值 是对象的复制 是原有对象的引用,并不产生新的对象
类型扩展 不易扩展 容易扩展,方便与类型扩展

注:GC(Garbage Collector,垃圾回收器)是一种自动回收内存的机制,释放已经不再使用的对象的内存空间。

在.NET平台中,我们的托管代码一般都不再关心内存的管理,一切都有CLR(Common language Runtime)去帮我们完成了。当我们开辟内存空间用来创建对象时,使用new关键字,这时CLR会分配一块内存存放对象,大部分时候,我们都不用自己去释放内存空间,而是由CLR在某个适当的时候帮我们释放掉。 

  为什么要GC?

  1.创建新对象开辟内存空间,在使用完后需要释放内存,提高性能

  2.避免开发人员直接操作内存,提高安全性

  GC(回收)过程

  我们运行.NET程序后,OS Loader首先识别出IL(中间语言),然后会加载CLR的核心库,进行一系列的必要处理后,CLR来到我们编写的代码入口处执行。

  当我们的在代码中使用new操作符创建class时,CLR便在叫作GC堆(GC Heap)的内存区域上分配一块内存存放我们的对象,若对象的Size超过85K字节时,考虑到性能原因,将对象创建在LOH(Large Object Heap)上而不是GC堆上【注1】,若我们在class中定义了析构函数来释放非托管资源【注2】,则CLR会在一个叫做终结器队列(Finalizer Queue)的地方添加一个指向该class的项。

  我们的程序在运行的过程,在某个时候需要进行垃圾回收了【注3】,首先GC会暂时挂起所有线程,然后确定对象引用的roots【注4】,并根据引用关系创建出由roots出发可以达到的对象形成的对象图,这些对象暂时还在使用,而那些已创建的却不在对象图中的对象则是不可达到的,也就是垃圾了,属于要回收的对象。随后将仍然使用的对象移动到存活期更久的区域【注5】,更改区域指针以回收对象,压缩内存去除内存空隙,并修复对移动的仍存活对象的引用指针,对于有析构函数的对象,则第一次回收时不会回收,而是将其在终结器队列中移除,并添加到另一个标为准备终止的对象列表中,另一个GC线程会调用此列表指向的对象的Finalize(),回收非托管资源,然后将项从列表中移除,下一次的GC才会真正回收掉该对象。

  注1:对象创建在Heap上的细节

  1): 为了更高效的进行GC,.NET将GC堆分成了3个代,Gen0,Gen1和Gen2。

  2): 这3个代只是逻辑上的划分,在内存中,他们的地址是连续的。

  3): Gen0和Gen1之和的大小大约是16M(workstation GC模式下)和64M(server GC模式下)。

  4): 新创建对象Size小于85k位于Gen0上,大于85K的则创建在LOH上。

注2:定义析构函数释放非托管资源

  Finalize方法是用来释放对象中使用的非托管资源,他是作为Dispose()方法的一种安全防护措施,即代码中没有显示的调用Dispose()来释放非托管资源时,GC时调用Finalize方法来释放,Finalize方法中并不直接释放非托管资源,而是调用Dispose(false)来释放。自.NET2.0起,C#中不能直接override Finalize方法,是通过析构函数来实现,析构函数在IL中会被解释为:

protected override void Finalize()
{
    try
    {
        //执行自定义资源清理操作
    }
    finally
    {
        base.Finalize();
    }
}

  默认情况下,一个类是没有析构函数的,那么在GC时是不会调用其Finalize()方法的。

  注3:GC发生的时机

  1)当Gen0的内存使用达到一个阈值时,将引发Gen0的GC,同理Gen1达到时,会Gen0和Gen1同时GC,若Gen2达到时,则会引发Full GC

  2)Windows报告内存不足时

  3)调用GC.Collect时

  4)其他情况:CLR卸载AppDimain,物理内存不足等

  注4:确定对象引用根

  对象的引用根主要来自于:FInalize Queue,CPU寄存器中的对象指针,全局对象、静态变量、局部对象、函数调用参数等。

  注5: GC时对象的转移

  1)Gen0 GC时,会将Gen0中存活的对象整体移动到Gen1中,然后压缩Gen1,使Gen1中的内存连续,同理Gen1中移动到Gen2。

  2)Gen2 GC时,此时发生的GC也称为Full GC,会回收整个Heap上的对象,Gen2上的对象将不再移动,而是压缩内存空间。

  3)LOH中的对象在Full GC时被回收,但其内存不会被压缩,而是使用一个空闲列表free list记录LOH中的空闲空间,对释放出来的空间进行管理。

  4)若对象是pinned object,则此对象不能被移动, 会造成内存碎片。

C#中值类型和引用类型相关推荐

  1. java引用类型和值类型_[Java教程]JavaScript中值类型和引用类型的区别

    [Java教程]JavaScript中值类型和引用类型的区别 0 2017-02-24 00:00:35 JavaScript的数据类型分为两类:原始类型和对象类型.其中,原始类型包括:数字.字符串和 ...

  2. java值类型和引用类型 == 比较,Java中值类型和引用类型的比较与问题解决

    一.问题描述 前几天因为一个需求出现了Bug.说高级点也挺高级,说白点也很简单.其实也就是一个很简单的Java基础入门时候的值类型和引用类型的区别.只是开发的时候由于自己的问题,导致小问题的出现.还好 ...

  3. 彻底理解C#中值类型和引用类型的区别

    ref:http://space.itpub.net/12639172/viewspace-501584 特点 值类型 引用类型 变量存放的内容 实际值 引用 内存单元 内联(堆栈) 堆 默认值 0 ...

  4. C#中值类型和引用类型的区别

    1.    值类型的数据存储在内存的栈中:引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的 地址. 2.     值类型存取速度快,引用类型存取速度慢. 3.     值类型表示实际数据, ...

  5. 值类型与引用类型的区别

    可以这样理解: 值类型保存的是具体的值 引用类型保存的是值的地址 例如 int a = 1; int b = a; b++; 这时b为2,a仍然是1 再看引用类型,例如有个类型是 User User ...

  6. java 值类型与引用类型_JAVA 关于值类型和引用类型的区别

    Java中值类型和引用类型的不同? [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值,那么调用这个方法是传入的变量的值也将改变.值类型 ...

  7. 述说C#中的值类型和引用类型的千丝万缕

    关于值类型和引用类型方面的博客和文章可以说是汗牛充栋了,今天无意中又复读了一下这方面的知识,感觉还是有许多新感悟的,就此时间分享一下: CLR支持两种类型:值类型和引用类型,看起来FCL的大多数类型是 ...

  8. 值类型和引用类型在栈和堆中的分配

      类型基础及背后的工作原理   数据在内存中的分配与传递    值类型和引用类型它们在内存分配与传递上的区别 内存分配 首先要了解一下内存中栈和堆的概念.     栈(Stack) ##栈是一种先进 ...

  9. [你必须知道的.NET]第九回:品味类型---值类型与引用类型(中)-规则无边

    发布日期:2007.5.28 作者:Anytao ©2007 Anytao.com ,原创作品,转贴请注明作者和出处. 接上回[第八回:品味类型---值类型与引用类型(上)-内存有理]的探讨,继续我们 ...

最新文章

  1. Deep Manta:单目图像下2d到3d由粗到精的多任务网络车辆分析
  2. Android中Google Drive显示黑屏问题分析
  3. 使用CUDA计算Haar小波变换
  4. Windows RDP协议 Fuzzing 漏洞挖掘研究
  5. powerbi 线性回归_Power BI二月新增图表及课程福利
  6. Vue实现仿音乐播放器10-更多按钮实现下拉刷新
  7. 你对一个程序员有多尊重
  8. java上传和下载文件代码_JavaWeb中上传和下载文件实例代码
  9. 2021年程序员可以做哪些副业?
  10. 客户端版本和服务器版本上传软件
  11. python帮助文档在哪_python文档在哪里
  12. iOS开发之段落文字排版的属性与细节
  13. jq实现文字个数限制_限制字符输入数功能(jquery版和原生JS版)
  14. WSL:适用于 Linux 的 Windows 子系统
  15. opencv裁剪图像(不规则裁剪)
  16. 好用的android剪辑软件,最好用的视频剪辑app软件有哪些?自媒体人都在用的六款app软件...
  17. 赛尔号登录器显示服务器未开启,赛尔号登录界面改版啦!
  18. Microsoft Outlook设置GMail谷歌邮箱
  19. java黄金分割点游戏_结对编程——Java实现黄金分割点游戏
  20. stm32 移植 FreeRTOS

热门文章

  1. grads 相关系数_基于小波变换的多聚焦图像融合算法
  2. 阿里云服务器购买及宝塔管理和如何部署springboot项目
  3. 先来先服务调度算法(C++实现)
  4. css3 手机信号,CSS3 无线路由器连接信号动画
  5. C语言初始化错误怎么办,结构体变量的初始化错误
  6. iOS - 利用 UIBezierPath 绘制圆弧
  7. 4 关卡流 进阶_儿童桌游要不要鸡血的过关?关卡制儿童桌游介绍与方法论
  8. python自带编译器闪退_python自带编译器在写入文件时闪退,或者一步步执行到写入时提示8170。解决办法:...
  9. linux 文件服务,Linux操作系统之文件服务(ftp、nfs)
  10. 一次Ping1000个IP会怎么样?