zoukankan      html  css  js  c++  java
  • C#中值类型和引用类型

    概念:

    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中会被解释为:

  • 相关阅读:
    VScode 修改中文字体
    missing KW_END at ')' near '<EOF>'
    SQL inner join, join, left join, right join, full outer join
    SQL字符替换函数translater, replace
    SQL COOKBOOK SQL经典实例代码 笔记第一章代码
    sqlcook sql经典实例 emp dept 创建语句
    dateutil 2.5.0 is the minimum required version python
    安装postgresql后找不到服务 postgresql service
    Postgres psql: 致命错误: 角色 "postgres" 不存在
    【西北师大-2108Java】第十六次作业成绩汇总
  • 原文地址:https://www.cnblogs.com/zywf/p/4567293.html
Copyright © 2011-2022 走看看