简介
这篇文章我们将介绍一些方法参数传递行为在堆与栈中的影响。前几节我们介绍了堆与栈的基本工作原理,程序执行时值类型与引用类型在堆栈中的存储。另外,我们已经介绍了一些关于指针的基本知识。这一节中参数传递对堆栈的影响很重要,下面会慢慢道来。
参数,大画面
下面是当代码运行时会产生的一个详细过程。上几节已经介绍过当一个方法被调用时会产生的基本情况,让我们来看一下更加详细的内容。
当我们调用一个方法时会发生以下情形:
栈会分配一块内存空间给程序执行所需要的信息(我们叫它栈结构Stack Frame)。一个栈结构包含方法调用地址(指针),它以一个GOTO指令的形式存在栈里。因此,当线程序执行完方法(method),它会知道怎么样返回进而曳继续执行代码。
方法的所有参数将被复制到栈里,这是我们将要更加详细介绍的部分。
控制被传递到JIT编译过的方法里,同时线程开始执行代码。此时,我们将有另一个方法呈现在栈结构的“回调栈”里。
代码:
[csharp] view plaincopy
public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}
像前几节介绍的,值类型和引用类型在栈里的存储是不同的。栈为任何值类型创建副本,栈也为任何引用类型的指针创建副本。
值类型传递
下面是值类型传递在栈里的内幕。
首先,当我们传递一个值类型变量时,栈会为它分配一块内存空间并把值类型变量的值存储进去。看下面的代码:
[csharp] view plaincopy
class Class1
{
public void Go()
{
int x = 5;
AddFive(x);
Console.WriteLine(x.ToString());
}
public int AddFive(int pValue)
{
pValue += 5;
return pValue;
}
}
当代码执行时,栈为x分配一块内存空间并存储值5
然后,AddFive()被放到栈上,同时栈分配内存空间给参数pValue并复制x的值给它。
当AddFive()执行完成,线程被传递回Go()。同时因为AddFive()执行完,它的参数pValue也实质上被移除。
所以结果是5是合理的。关键点是任何被传递的值类型参数仅是一个碳复制,因为我们希望保护原始变量的值。
有一点要记住的是,如果我们有一个非常庞大的值类型(如,庞大的struct类型)传递到栈里,当处理器循环复制它并循环占有栈空间时将会非常耗资源。栈没有无限的空间去使用,就像用水杯不断的接水早晚会溢出一样。Struct类型可以变得非常庞大,我们要小心并清醒的使用它。
下面是一个比较大的struct结构类型:
[csharp] view plaincopy
public struct MyStruct
{
long a, b, c, d, e, f, g, h, i, j, k, l, m;
}
让我们看看执行下面代码Go()方法时再到DoSomething()方法会发生的情况:
[csharp] view plaincopy
public void Go()
{
MyStruct x = new MyStruct();
DoSomething(x);
}
public void DoSomething(MyStruct pValue)
{
// 省略具体实现....
}
这可能会非常低效。想像一下如果我们传递MyStruct几千次,它会怎么样让程序死掉。
那么,我们怎么才能回避这样的问题呢?那就是仅传递原始值类型的引用。
public void Go()
{
MyStruct x = new MyStruct();
DoSomething(ref x);
}
public struct MyStruct
{
long a, b, c, d, e, f, g, h, i, j, k, l, m;
}
public void DoSomething(ref MyStruct pValue)
{
// 省略实现....
}
这样就能节省内存并提升内存使用效率
唯一需要注意的是传递引用时我们在访问原始变量x的值,任可对pValue的改变都会影响到x。
下面的代码会将x改变成"12345",因为pValue.a实际上指向原始x声明时所在的内存地址。
[csharp] view plaincopy
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;
}
阅读(1155) | 评论(0) | 转发(0) |