【问题标题】:Can reference types be allocated on stack?可以在堆栈上分配引用类型吗?
【发布时间】:2014-10-11 08:09:39
【问题描述】:

考虑以下代码:

class Point
{
   public int position;
}

这里的int位置将被分配到堆上,即使它是一个值类型。

但我的问题是关于相反的情况,请考虑以下代码:

struct Person
{
   public string name;
}

这里将字符串名称分配在堆上还是栈上?

TIA

【问题讨论】:

标签: c# heap-memory value-type stack-memory reference-type


【解决方案1】:

引用类型实际实例对象分配在堆上,其引用变量分配在堆栈上。

就像脑筋急转弯: 当我们将值类型转换为引用类型时,例如和对象(一切都是 .net 中的对象)或接口(引用类型)它正在实现然后值类型被装箱,这意味着复制到堆并被引用从堆栈中。 如果我们将对象转换回值类型,它就会被拆箱回值类型并完全复制到堆栈中。 有些人倾向于错误地将这种情况视为在堆上分配的引用类型。

【讨论】:

    【解决方案2】:

    没有。对字符串的引用将在分配 Person 的地方分配。字符串本身将在堆上分配。事实上,每次你说 new T 其中 T 是一个类时,对象都会在堆上分配。

    【讨论】:

    • 您的意思是,在第二个示例中,如果 Person 是类,那么字符串的引用和字符串数据是否都位于堆上?
    • 没有 Person 是一个结构。结构的问题是它们并不总是分配在堆栈上。它们被内联分配到任何使用它们的地方,可以在一个类、堆栈或另一个结构中。
    • 我画了一张图来告诉你我到现在为止的理解。 pixentral.com/pics/1lgTw2M0rd68InSHj0ILKa1Cy1vYx0.png
    【解决方案3】:

    在你的情况下 - 字符串在堆上分配。

    但引用类型可以在堆栈上分配。

    例如,数组可以分配为:

    private static void Main(string[] args)
            {
                unsafe
                {
                    const int size = 123;
                    var mgmtArray = new long[size];
                    mgmtArray[0] = 12345;
    
                    void* refAddr = Unsafe.AsPointer(ref mgmtArray);
    
                    long mgmtArrAddr = *(long*)refAddr;
                    long mtAddr = *(long*)mgmtArrAddr;
                    long arrSize = ((int*)mgmtArrAddr)[2];
    
                    Console.WriteLine("Addr ref: {0:x}", (long)refAddr);
                    Console.WriteLine("Mgmt array addr: {0:x}", mgmtArrAddr);
                    Console.WriteLine("MT: {0:X}", mtAddr);
                    Console.WriteLine($"{nameof(arrSize)}: {arrSize}");
    
                    long* stackPtr = stackalloc long[size * 2];
    
                    stackPtr[0] = 0; //sync block
                    stackPtr[1] = mtAddr;
                    ((int*)stackPtr)[4] = size;
                    stackPtr++;
    
                    long** stackPtrRef = &stackPtr;
    
                    var pointer = new MgmtPointer<long[]>(Unsafe.Read<long[]>(stackPtrRef));
    
                    long[] arrayOnStack = Unsafe.Read<long[]>(stackPtrRef);
    
                    arrayOnStack[0] = 54321;
    
                    Console.WriteLine("-----");
    
                    Console.WriteLine($"In heap: {mgmtArray[0]}"); //12345
                    Console.WriteLine($"In stack: {arrayOnStack[0]}"); //54321
                    Console.WriteLine($"arrayOnStack len: {arrayOnStack.Length}");
                }
            }
    

    也适用于其他引用类型,但有一些变化。

    【讨论】:

      猜你喜欢
      • 2014-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-18
      • 2017-05-16
      • 2018-09-09
      • 2013-10-18
      相关资源
      最近更新 更多