namespace 实
{
    class test
    {    }    class Program
    {
        static test DO()
        {
            test bar = new test();
            return bar;
        }
        static void Main(string[] args)
        {
            test Newbar = DO();
        }
    }
}
问题1:运行时调用了DO()这个方法,DO()这个方法return了一个test的实例bar然后赋值给Newbar,bar是局部变量再函数运行完以后就撤消了那为什么Newbar还能正常使用呢?
问题2:还有return语句再执行以后函数不是已经完成了吗?那么它是赋值的 呢 return 的数据怎么存储的呢

解决方案 »

  1.   

    http://www.cnblogs.com/jintianzhang/archive/2011/03/29/1998706.html
    理解一下
      

  2.   

    1 楼我看了你的博客了 
    我想问一个问题你说值类型都是在堆栈上分配内存

    public class a 
    {
     public int aa; // 再实例化a 以后 这个aa 是存储再那呢 ????

    还有我问的 RUTURN 这个问题 是这个意思 函数调用 是压栈  那么最先弹出的时候 return 是吧 那么他返回的 那个变量是不是 再栈中临时开辟一块空间用来储存呢
      

  3.   

    问题1:运行时调用了DO()这个方法,DO()这个方法return了一个test的实例bar然后赋值给Newbar,bar是局部变量再函数运行完以后就撤消了那为什么Newbar还能正常使用呢?
    ----------------------------------------------------------------------
    因为bar是引用类型,DO那个方法返回的是bar 的引用,
    bar所占的空间在DO方法返回时是会释放的,但实际内容是不释放的,
    Newbar 能正常实际用因为获取的是对应引用内的东西,就是实际内容。
      

  4.   

     public int aa; // 再实例化a 以后 这个aa 是存储再那呢 ????
    --------------
    aa 存在托管堆,值类型并不总是存在堆栈上的
      

  5.   

    问题2:还有return语句再执行以后函数不是已经完成了吗?那么它是赋值的 呢 return 的数据怎么存储的呢
    ---------------------
    当方法有返回值并且有变量接收的时候,会有压栈和出栈两个操作压栈指的记忆方法的返回值,出栈是将返回值赋给对应的变量
      

  6.   

    不需要考虑堆栈问题,考虑那个会把自己搞晕的。.NET中不需要考虑内存释放,都是自动管理的。只有非托管代码才需要考虑。
    值类型是直接存放在内存地址里,而引用类型是存放在2处,内存地址里先存放引用地址,然后定位到另一个地址的连续内存空间,那才是引用类型的实际内容。
    因此访问值类型例如int,就是直接一次寻址,而访问引用类型如chass a,那就是二次寻址。return返回的都是第一次寻址的结果,值类型的就返回实际值,而引用类型则返回引用地址。考虑到32位操作系统的引用地址只有32位整型长度,因此这个返回值很小。每次为这个返回值开辟新的内存空间存放也没任何关系,几乎感觉不到内存的使用。bar是局部变量再函数运行完以后就撤消,但是撤销的是bar的引用地址所占用的内存空间而已,第二级地址的内容还没撤销,因为又有新的对象Newbar指向了它,Newbar里存放了和bar一样的引用地址,2个变量虽然第一级地址不同,但是同时指向同一个引用地址。只有当某个引用地址不被任何对象引用,它才会被释放,这是.NET的潜规则。
      

  7.   

    那样的话,连压栈动作也不会有,这2个动作必须是配对的,否则整个程序的后续操作都要出错。PS:如果你一定要看堆栈,将代码编译后看IL语言,那个会显示详细的堆栈操作,但是你肯定会看晕。
    分别编译2个操作,一个接收,一个不接受,IL语言会显示2种,接收返回值的,有堆栈动作代码,而不接收返回值的,直接结束,无任何堆栈操作。
      

  8.   

    ...看了你们说的我说一下我的理解哈
    有返回值的时候 函数压栈 首先记忆这个返回值 并且给他分配好空间比如说空间A 运行RETURN 时 系统把返回值复制到 A 里...然后函数 结束 ...把A的值 通过= 赋值给 主调函数的变量 然后A 撤销....是不是 ?
      

  9.   

    不知道你的分配空间A是指什么空间,如果是CPU堆栈空间,那么你的理解没问题,如果是内存空间,那么你的理解就有问题了。
      

  10.   

    c#是.net clr托管开发语言的一种。
    .net的托管开发,关键是托管了内存的管理,你不需要自己管理内存,而是交给CLR来管理,有垃圾回收。这里,创建的类型都继承自Object,并分为两类:
    值类型和引用类型
    值类型在=的时候进行值拷贝,对象的深度复制。
    引用类型的对象永远是在堆上分配内存,你使用的只能是对象的引用。所以,你可以认为.net的class对象,都是指针操作的。为什么说是指针呢,因为c++中的指针可以指向NULL而引用不可以,c#的这个叫做引用,但和指针有点不同是除了对象和null其他不能指。相关值类型和引用类型的连接
    http://msdn.microsoft.com/zh-cn/library/4d43ts61(v=vs.90).aspx
    http://www.sosuo8.com/article/show.asp?id=2184
    http://www.cnblogs.com/Autumoon/archive/2008/08/18/1270685.html
      

  11.   

    一个变量 bar 它自身并不就是最终的对象,它只是引用对象而已。当没有引用,对象将来就会被GC自动回收。而既然有引用,那么bar 引用它,随后 Newbar 也引用它,没有什么不好理解的。bar变量没有了,不代表着对象没有引用了。
      

  12.   

    堆栈只是一小部分而已,内存很大部分是数据,只有小部分用作堆栈。这部分堆栈空间由CPU快速访问,无需申请或释放,空间是一次性分配好的,为了快速,有时会直接在CPU中缓存。
    所以你没必要对堆栈空间考虑过多,堆栈的空间要是频繁申请或释放,会大大影响速度的。
      

  13.   

    看了你们说的我说一下我的理解哈
    有返回值的时候 函数压栈 首先记忆这个返回值 并且再内存堆栈上分配A 运行RETURN 时 系统把返回值复制到 A 里...然后函数 结束 ...把A的值 通过= 赋值给 主调函数的变量 然后A 撤销....是不是 ?