C#内存管理(二)

本文详细解释了C#中值类型和引用类型在内存分配、生命周期及作用域上的区别,包括栈内存与堆内存的使用,以及如何影响代码性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个操作发生在栈的顶部,请注意我们看到已经有很多成员之前被压入到栈中了。首先是方法的本身先被压入栈中,紧接着是参数入栈。然后是通过AddFive()里面的指令来执行函数。函数执行的结果同样也需要分配一些内存来存放,而这些内存也分配在栈中。函数执行结束后,就要将结果返回。最后,通过删除AddFive()的指针来清除所有之前栈中有关于函数运行时分配的内存。并继续下一个函数(可能之前就存在在栈中)。在这个例子中,我们的结果存储在栈中。事实上,所有函数体内的值类型声明都会分配到栈中。但是现在有些值类型也被分配在堆中。记住一个规则,值类型总是出现在声明它们的地方。如果一个值类型声明在函数体外,但是存于一个引用类型内,那么它将跟这个引用类型一样位于堆中。这里用另外的一个例子来说明这个问题:

public class MyInt{     
       public int MyValue;
}
public MyInt AddFive(int pValue){
        MyInt result = new MyInt();
        result.MyValue = pValue + 5;
        return result;
}

现在这个函数的执行跟先前的有了点不同。这里的函数返回是一个MyInt类对象,也就是说是一个引用类型。引用类型是被分配在堆中的,而引用的指针是分配在栈中。

在AddFive()函数执行结束后,我们将清理栈中的内存。

在这里我们看到除了栈中有数据,在堆中也有一些数据。而堆中的数据将被垃圾回收器回收。当我们的程序需要一块内存并且已经没有空闲的内存可以分配时,垃圾回收器开始运行。垃圾回收器会先停止所有运行中的线程,扫描堆中的所有对象并删除那些没有被主程序访问的对象。垃圾回收器将重新组织堆中的所有空闲的空间,并调整所有栈中和堆中的相关指针。就像你能想到的那样,这样的操作会非常的影响效率。因此这也是为什么我们要强调编写高性能的代码。好,那我要怎么样去做呢?

当我们在操作一个引用类型的时候,我们操作的是它的指针而不是它本身。当我们使用值类型的时候我们使用的是它本身,这个很明显。我们看一下代码:

public int ReturnValue() {
        int x = new int();
        x = 3;
        int y = new int();
        y = x;
        y = 4;
        return x;
     }

这段代码很简单,返回3。但是如果我们改用引用类型MyInt类,结果可能不同:

public class MyInt {
        public int MyValue;
     }
     public int ReturnValue2() {
        MyInt x = new MyInt();
        x.MyValue = 3;
        MyInt y = new MyInt();
        y = x;
        y.MyValue = 4;
        return x.MyValue;
     }

这里的返回值却是4。为什么呢? 想象一下,我们之前讲的内容,我们在操作值类型数据的时候只是操作该值的一个副本。而在操作引用类型数据的时候,我们操作的是该类型的指针,所以y = x就修改了y的指针内容,从而使得y也指向了x那一部分栈空间。所以y.MyValue = 4 => x.MyValue = 4。所以返回值会是4 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值