2019.03.20 读书笔记 值类型与引用类型以及为什么装箱会性能耗损

什么是值类型和引用类型

  • 什么是值类型:
    • 所有的结构都是抽象类型System.ValueType的直接派生类,而System.ValueType本身又是直接从System.Object派生的。根据定义所知,所有的值类型都必须从System.ValueType派生,所有的枚举都从System.Enum抽象类派生,而后者又从System.ValueType派生。  
    •  所有的值类型都是隐式密封的(sealed),目的是防止其他任何类型从值类型进行派生。       
  • 什么是引用类型:
    • 在c#中所有的类都是引用类型,包括接口。

 

 

区别和性能

  • 区别:
    • 值类型通常被人们称为轻量级的类型,因为在大多数情况下,值类型的的实例都分配在线程栈中,因此它不受垃圾回收的控制,缓解了托管堆中的压力,减少了应用程序的垃圾回收的次数,提高性能。
    • 所有的引用类型的实例都分配在托管堆上,c#中new操作符会返回一个内存地址指向当前的对象。所以当你在创建个一个引用类型实例的时候,你必须要考虑以下问题:
      • 内存是在托管堆上分配的
      • 在分配每一个对象时都会包含一些额外的成员(类型对象指针,同步块索引),这些成员必须初始化
      • 对象中的其他字节总是设为零
      • 在分配对象时,可能会进行一次垃圾回收操作(如果托管堆上的内存不够分配一次对象时)
  • 性能:
    • 在设计一个应用程序时,如果都是应用类型,那么应用程序的性能将显著下降,因为这会加大托管堆的压力,增加垃圾回收的次数。
    • 虽然值类型是一个轻量级的类型,但是如果大量的使用值类型的话,也会有损应用程序的性能(例如下面要讲的装箱和拆箱操作,传递实例较大的值类型,或者返回较大的值类型实例)。
    • 在传值过程中,无论是值类型还是引用类型,都是分配一个变量空间,存入值类型,值类型传递的是本身数据,而引用类型传递的是地址(长度由系统默认),但是在运算时 ,值类型变量直接运算,而引用类型需要索引从堆中找到引用类型数据,再读取到堆栈中计算。

常见误区

    • 引用类型分配在托管堆上,值类型分配在线程栈上:其实这种说法的前半部分是对的,后半部分是错的。因为变量的值在它声明的位置存储的,所以假如某一个引用类型中有一个值类型的变量, 那么该变量的值总是和该引用类型的对象的其它数据在一起,也就是分配在堆上。(只有局部变量(方法内部声明的变量)和方法的参数在栈上)
    • 结构是轻量级的类:这种错误的信息主要是因为有人认为值类型不应该有方法或者其它有意义的行为-它们应该作为简单的数据转移来使用,所以很多人分不清DateTime到底是值类型还是引用类型。
    • 对象在c#中默认的是引用传递的:其实在调用方法的时候,参数值(对象的一个引用)是以传值得方式传递的,如果你想以引用方式传递的话,可以使用ref或者out关键字。

 

装箱步骤:

1.会为值类型在托管堆中分配内存,除了值类型本身所分配的内存外,内存总量还要加上类型对象指针和同步索引所占用的内存

2.将值类型的值复制到新分配的堆中

3.返回已经成为引用类型的对象的地址。

所以避免用“abc”+9,而应该写成“abc”+9.tostring(),前者对9走了装箱操作,后者是非托管代码Number.FormatInt32.

 

转载于:https://www.cnblogs.com/kafeibuhuizui/p/10566605.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值