搜索

查看: 3076|回复: 11

[ASP.NET] ASP.NET堆和栈二之值类型和引用类型的参数传递和内存分配

[复制链接]
发表于 2023-5-4 11:32:39 | 显示全部楼层 |阅读模式
Editor 2023-5-4 11:32:39 3076 11 看全部
".NET的堆和栈"系列:
ASP.NET堆和栈一之基本概念和值类型内存分配
ASP.NET堆和栈二之值类型和引用类型参数传递和内存分配
ASP.NET堆和栈三之引用类型对象拷贝和内存分配
ASP.NET堆和栈四之对托管和非托管资源垃圾的回收和内存分配
在" ASP.NET堆和栈一之基本概念和值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配。我们知道:当执行一个方法的时候,值类型实例会在"栈"上分配内存,而引用类型实例会在"堆"上分配内存,当方法执行完毕,"栈"上的实例由操作系统自动释放,"堆"上的实例由.NET Framework的GC进行回收。而本篇的重点要放在:值类型和引用类型参数的传递,以及内存分配。
传递值类型参数
class Class1
{
    public void Go()
    {
        int x = 5;
        AddFive(x);
         
        Console.WriteLine(x.ToString());
   
    }
     
    public int AddFive(int pValue)
    {
        pValue += 5;
        return pValue;
    }
}
大致过程如下:
1、值类型变量x被放到"栈"上。

202281392658361.png

202281392658361.png


2、开始执行AddFive()方法,值类型变量pValue被放到"栈"上,并把x的值赋值给pValue,pValue的值变成了5。

202281392658362.png

202281392658362.png


3、继续执行AddFive()方法,pValue的值变成了10。

202281392658363.png

202281392658363.png


4、执行完AddFive()方法,释放pValue的内存,"栈"指针回到x,线程重新回到Go()方法中。

202281392658364.png

202281392658364.png


输出结果:5

以上,在传递值类型参数x的时候,实际上是把x一个字节一个字节地拷贝给pValue。
传递容易造成"栈溢出"的值类型参数,在值类型参数前加关键字ref
public struct MyStruct
{
    long a, b, c, d, e, f, g, h, i, j, k, l, m;
}
public void Go()
{
    MyStruct x = new MyStruct();
    DoSomething(x);
}
public void DoSomething(MyStruct pValue)
{
    // DO SOMETHING HERE....
}
假设以上的值类型struct足够大,而x和pValue都会被分配到"栈"上,这时可能造成"栈溢出"。

202281392658365.png

202281392658365.png


如何避免呢?
--解决办法是让DoSomething传递一个ref类型参数。这样写:
public struct MyStruct
{
    long a, b, c, d, e, f, g, h, i, j, k, l, m;
}
public void Go()
{
    MyStruct x = new MyStruct();
    x.a = 5;
    DoSomething(ref x);
   
    Console.WriteLine(x.a.ToString());
               
}

public void DoSomething(ref MyStruct pValue)
{
    pValue.a = 12345;
}
使用ref后,执行DoSomething(ref x),是把x的地址赋值给了pValue,即pValue和x指向了同一个引用地址。当改变pValue的值,变化也会反映到x中。         

202281392658366.png

202281392658366.png


输出结果:12345

以上,为了避免"大型"值类型参数传递时造成的"栈溢出",可以在值类型前面加ref关键字,于是,在传递值类型参数x的时候,实际上是把x本身的栈地址拷贝给pValue,x和pValue指向同一个栈地址。
传递引用类型参数
传递引用类型参数的道理和在传递的值类型参数前面加ref关键字是一样的。
public class MyInt
{
    public int MyValue;
}
public void Go()
{
    MyInt x = new MyInt();
    x.MyValue = 2;
   
    DoSomething(x);
   
    Console.WriteLine(x.MyValue.ToString());
}
public void DoSomething(MyInt pValue)
{
    pValue.MyValue = 12345;
}
输出结果:12345

以上大致过程是这样:
1、在托管堆上创建一个MyInt类型的实例
2、在栈上创建一个MyInt类型的变量x指向堆上的实例
3、把托管堆上的公共字段MyValue赋值为2
4、通过DoSomething(x)方法,把x的引用地址赋值给pValue,即pValue和x指向同一个引用地址
5、改变pValue的值,也会反映到x上
以上,在传递引用类型参数x的时候,实际上是把x指向托管堆实例的引用地址拷贝给pValue,x和pValue指向同一个托管堆实例地址。
传递引用类型参数,在引用类型参数之前加关键字ref
public class Thing
{
   
}

public class Animal:Thing
{
    public int Weight;
}

public class Vegetable:Thing
{
    public int Length;
}
public void Go()
{
    Thing x = new Animal();
   
    Switcharoo(ref x);
   
    Console.WriteLine("x is Animal    :   " + (x is Animal).ToString());
   
    Console.WriteLine("x is Vegetable :   " + (x is Vegetable).ToString());
}

public void Switcharoo(ref Thing pValue)
{
    pValue = new Vegetable();
}
输出结果:
x is Animal    :   False
x is Vegetable :   True

以上大致过程是这样:
1、在托管堆上创建Animal对象实例。
2、在栈上创建类型为Thing的x变量指向Animal实例的引用地址。
3、通过Switcharoo(ref x)方法把x本身的地址赋值给pValue,至此,pValue和x指向了相同的栈内存地址,任何一方的变化都会反映到另外一方。

202281392658367.png

202281392658367.png


4、在Switcharoo(ref Thing pValue)内部,在托管堆上创建Vegetable对象实例。
5、pValue指向Vegetable实例,也就相当于x指向Vegetable实例。

202281392658368.png

202281392658368.png


以上,当在引用类型参数之前加上关键字ref,再传递,是把x本身的栈地址拷贝给pValue,x和pValue指向同一个栈地址。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对知鸟论坛的支持。如果你想了解更多相关内容请查看下面相关链接
回复

使用道具 举报

发表于 2023-6-29 14:03:11 | 显示全部楼层
无人岛屿颈 2023-6-29 14:03:11 看全部
既然你诚信诚意的推荐了,那我就勉为其难的看看吧!知鸟论坛不走平凡路。
回复

使用道具 举报

发表于 2023-6-29 18:24:18 | 显示全部楼层
六翼天使494 2023-6-29 18:24:18 看全部
楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
回复

使用道具 举报

发表于 2023-6-29 22:03:46 | 显示全部楼层
落败的青春阳落s 2023-6-29 22:03:46 看全部
其实我一直觉得楼主的品味不错!呵呵!知鸟论坛太棒了!
回复

使用道具 举报

发表于 2023-6-29 23:52:22 | 显示全部楼层
123456848 2023-6-29 23:52:22 看全部
楼主发贴辛苦了,谢谢楼主分享!我觉得知鸟论坛是注册对了!
回复

使用道具 举报

发表于 2023-7-1 03:10:47 | 显示全部楼层
123456833 2023-7-1 03:10:47 看全部
楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
回复

使用道具 举报

发表于 2023-7-3 07:29:21 | 显示全部楼层
米老鼠和蓝精鼠v 2023-7-3 07:29:21 看全部
楼主,大恩不言谢了!知鸟论坛是最棒的!
回复

使用道具 举报

发表于 2023-7-3 09:05:18 | 显示全部楼层
幸福341 2023-7-3 09:05:18 看全部
论坛不能没有像楼主这样的人才啊!我会一直支持知鸟论坛
回复

使用道具 举报

发表于 2023-7-3 16:36:04 | 显示全部楼层
心随674 2023-7-3 16:36:04 看全部
楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
回复

使用道具 举报

发表于 2023-7-3 20:28:48 | 显示全部楼层
贰十岁装成熟装s 2023-7-3 20:28:48 看全部
其实我一直觉得楼主的品味不错!呵呵!知鸟论坛太棒了!
回复

使用道具 举报

  • 您可能感兴趣
点击右侧快捷回复 【请勿灌水】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则 返回列表

RSS订阅| SiteMap| 小黑屋| 知鸟论坛
联系邮箱E-mail:zniao@foxmail.com
快速回复 返回顶部 返回列表