c#structs/classes stack/heap control?

Mat*_*Mat 13 c# heap stack memory-management

所以在c ++中它很容易.你想要在堆上分配任何类/结构,使用new.如果你想在堆栈上,不要使用新的.

在C#中,我们总是使用new关键字,并且根据它是结构还是类,它在堆栈或堆上分配(结构转到堆栈,堆到类) - 在某些应用程序中可以有更改设计时的巨大性能差异,只有那些对象才能进入真正属于那里的堆.

我想知道的是 - 是否有一种直接的方法来控制对象的分配位置,而不管它是否被声明为struct或class?我知道值类型(结构)可以装箱去堆(但装箱/拆箱会带来性能成本).有没有办法在堆栈上分配类?

此外,是否有任何机制来分配原始内存并使用像C++中的placement new这样的东西?我知道这打破了被管理的想法 - 但如果你可以使用你的自定义内存管理,它可以产生很大的性能差异.

我喜欢C#因为它的便利性,因为它是垃圾收集器和其他东西 - 但有时候,当处理应用程序的瓶颈时,可能需要更多地控制实际发生的事情.

任何提示/提示欢迎:)

编辑:性能示例:

struct Foo1
{
    public int i;
    public float f;
    public double d;
}

struct Foo2
{
   public Foo1[] bar;

   public void Init(){
        bar = new Foo1[100];
        for (int i = 0; i < 100; i++)
            bar[i] = new Foo1();
    }
}

class Program
{
    static void Main(string[] args)
    {
        DateTime time = DateTime.Now;
        Foo2[] arr = new Foo2[1000000];
        for (int i = 0; i < 1000000; i++)
        {
            arr[i] = new Foo2();
            arr[i].Init();
        }

        Console.WriteLine((DateTime.Now - time).TotalMilliseconds);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的机器需要1.8秒才能执行(注意实际上只有分配正在进行 - 没有参数传递)

如果Foo1从struct更改为class,则执行需要8.9秒!这慢了五倍

Bli*_*ndy 9

虽然在一般情况下确实总是在堆上分配对象,但C#确实可以让你下拉到指针级别以获得重型互操作或非常高性能的关键代码.

不安全的块中,您可以使用stackalloc在堆栈上分配对象并将它们用作指针.

引用他们的例子:

// cs_keyword_stackalloc.cs
// compile with: /unsafe
using System; 

class Test
{
   public static unsafe void Main() 
   {
      int* fib = stackalloc int[100];
      int* p = fib;
      *p++ = *p++ = 1;
      for (int i=2; i<100; ++i, ++p)
         *p = p[-1] + p[-2];
      for (int i=0; i<10; ++i)
         Console.WriteLine (fib[i]);
   }
}
Run Code Online (Sandbox Code Playgroud)

但请注意,您不需要声明整个方法不安全,您只需使用一个unsafe {...}块即可.


LBu*_*kin 6

您对值类型与引用类型的位置(堆栈对堆)的解释并不完全正确.

如果结构是引用类型的成员,那么它们也可以在堆上分配.或者,如果您在通过对象引用传递它们时将它们装箱.

您应该阅读http://www.yoda.arachsys.com/csharp/memory.html以更好地了解实际分配的不同类型的位置.

另外,在.Net中,你真的不应该关心类型的分配位置 - 正如Eric Lippert所写:堆栈是一个实现细节.你最好理解类型传递的语义(通过值,引用等).

此外,您似乎暗示在堆上分配对象比在堆栈上分配更昂贵.实际上,我认为复制值类型的性能成本超过了在堆栈上稍快分配的任何节省的好处.堆栈和堆之间的最大区别在于,在大多数CPU架构中,堆栈更有可能保留在CPU缓存中 - 从而避免缓存未命中.

这不是最重要的问题.您应该决定该类型是否应该具有按值传递的语义.如果没有 - 那么也许它应该是一个参考类型.