值类型和引用类型原理

本文深入探讨C#中值类型和引用类型的内存分配与赋值差异。值类型在栈中分配,赋值时复制数据;引用类型则在堆中分配,赋值时复制引用。通过实例解析线程栈和托管堆的工作机制,展示了对象地址与成员地址的关系,并解释了方法传参的本质。
摘要由CSDN通过智能技术生成

如果有不理解的地方,可以先看之前的两篇基础
C# 变量入门趣谈
线程堆栈(Thread Stack)和托管堆(Managed Heap)
C#方法传参原理(内存地址原理剖析)

需要先说明一下,此文所说的对象赋值和上文说的方法传参是一致的,方法传参其实就是把一个对象赋值给方法中的参数罢了。

值类型和引用类型

值类型和引用类型有什么根本的区别?
值类型以结构类型为例


在程序还没有执行到声明变量的时候,已经在内存的线程栈里,给所有的局部变量分配了内存空间地址,因为我的程序是x84,32位的,每个int是4个字节,所以每个栈空间的局部变量的内存地址,先压栈p1为0x00cfec1c,p1.x偏移了4个字节为0x00cfec20(对象p1和字段p1.x共占8个字节).而压栈p2的时候,p2的地址为p1的地址-8个,因为p2.x也要占4个字节,往后偏移4个字节.(如何理解压栈:你可以把它想象成一个箱子 数据就像你手中的包子 箱子本来是空的 你放个包子进去 包子就在箱子最底下了;再放包子进去 新放进去的包子就在第一个包子的上面点了 这个放包子的过程就是压栈)

关于偏移量?
对象的地址和成员的地址是有关系的,因此我们在写代码的时候能对象直接点出成员。在x86并且成员都占4个字节的时候,公式是成员n(第n个成员)的堆控件地址是对象地址+(n-1)*4。因为计算机的序号都是从0开始的。


值类型赋值,是复制赋值,赋值的仅仅为栈内存里存的数据。所以赋值后,就是两套地址不同的数据罢了,没有关联。

引用类型以类为例


指令&p可以查看栈地址,*p可以查看堆地址(指针地址)
在程序运行到断点的时候,已为所有的局部变量,在线程栈中都分配好地址。在new p1时才会给p1和p1.x分配了堆空间地址,并存放类型默认值,而p2得等到运行的时候才会分配堆堆(调试的时候会发现)。

这里要着重说一下,类是引用类型。类对象p2的堆地址存放在栈中如上图。当把p1赋值给p2的时候,因为栈内存空间中存放的数据p1对象堆里的地址,所以他就直接拿到p1的地址,于是乎p1和p2的栈内存数据同时指向同一块堆地址,此时,不管怎么改p1或者p2的字段值。他们永远是一个东西。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值