营; .NET:stackalloc [英] C# & .NET: stackalloc

查看:697
本文介绍了营; .NET:stackalloc的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有关于 stackalloc 操作符的功能的几个问题。

I have a few questions about the functionality of the stackalloc operator.

  1. 它是如何实际分配?我认为这确实是这样的:

  1. How does it actually allocate? I thought it does something like:

void* stackalloc(int sizeInBytes)
{
    void* p = StackPointer (esp);
    StackPointer += sizeInBytes;
    if(StackPointer exceeds stack size)
        throw new StackOverflowException(...);
    return p;
}

不过,我已经做了一些测试,我不知道它是如何工作的。我们不能确切地知道它做什么,它是如何做的,但我想知道的基本知识。

But I have done a few tests, and I'm not sure that's how it work. We can't know exactly what it does and how it does it, but I want to know the basics.

我认为堆栈分配(好吧,其实我的确定的这件事)比堆分配速度更快。那么,为什么这个例子:

I thought that stack allocation (Well, I am actually sure about it) is faster than heap allocation. So why does this example:

 class Program
 {
     static void Main(string[] args)
     {
         Stopwatch sw1 = new Stopwatch();
         sw1.Start();
         StackAllocation();
         Console.WriteLine(sw1.ElapsedTicks);

         Stopwatch sw2 = new Stopwatch();
         sw2.Start();
         HeapAllocation();
         Console.WriteLine(sw2.ElapsedTicks);
     }
     static unsafe void StackAllocation()
     {
         for (int i = 0; i < 100; i++)
         {
             int* p = stackalloc int[100];
         }
     }
     static void HeapAllocation()
     {
         for (int i = 0; i < 100; i++)
         {
             int[] a = new int[100];
         }
     }
 }

给出的 280〜蜱为堆栈分配的平均结果,与通常的 1-0蜱为堆分配?(在我的个人电脑,英特尔酷睿i7)。

gives the average results of 280~ ticks for stack allocation, and usually 1-0 ticks for heap allocation? (On my personal computer, Intel Core i7).

在我现在使用(英特尔酷睿2双核)的计算机,结果更有意义了previous的人(可能是因为的优化code 的未在VS选中) :      460〜蜱为堆栈分配,然后约 380蜱为堆分配

On the computer I am using now (Intel Core 2 Duo), the results make more sense that the previous ones (Probably because Optimize code was not checked in VS): 460~ ticks for stack allocation, and about 380 ticks for heap allocation.

但是,这仍然没有任何意义。为什么会这样呢?我想的是,我们不使用数组CLR的通知,所以也许它甚至不分配呢?

But this still doesn't make sense. Why is it so? I guess that the CLR notices that we don't use the array, so maybe it doesn't even allocate it?

推荐答案

一个情况下stackalloc快:

A case where stackalloc is faster:

 private static volatile int _dummy; // just to avoid any optimisations
                                         // that have us measuring the wrong
                                         // thing. Especially since the difference
                                         // is more noticable in a release build
                                         // (also more noticable on a multi-core
                                         // machine than single- or dual-core).
 static void Main(string[] args)
 {
     System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch();
     Thread[] threads = new Thread[20];
     sw1.Start();
     for(int t = 0; t != 20; ++t)
     {
        threads[t] = new Thread(DoSA);
        threads[t].Start();
     }
     for(int t = 0; t != 20; ++t)
        threads[t].Join();
     Console.WriteLine(sw1.ElapsedTicks);

     System.Diagnostics.Stopwatch sw2 = new System.Diagnostics.Stopwatch();
     threads = new Thread[20];
     sw2.Start();
     for(int t = 0; t != 20; ++t)
     {
        threads[t] = new Thread(DoHA);
        threads[t].Start();
     }
     for(int t = 0; t != 20; ++t)
        threads[t].Join();
     Console.WriteLine(sw2.ElapsedTicks);
     Console.Read();
 }
 private static void DoSA()
 {
    Random rnd = new Random(1);
    for(int i = 0; i != 100000; ++i)
        StackAllocation(rnd);
 }
 static unsafe void StackAllocation(Random rnd)
 {
    int size = rnd.Next(1024, 131072);
    int* p = stackalloc int[size];
    _dummy = *(p + rnd.Next(0, size));
 }
 private static void DoHA()
 {
    Random rnd = new Random(1);
    for(int i = 0; i != 100000; ++i)
        HeapAllocation(rnd);
 }
 static void HeapAllocation(Random rnd)
 {
    int size = rnd.Next(1024, 131072);
    int[] a = new int[size];
    _dummy = a[rnd.Next(0, size)];
 }

之间的code和,在问题的重要差异:

Important differences between this code and that in the question:

  1. 我们在运行多个线程。随着堆栈分配,它们分配自己的堆栈。随着堆分配,它们是从与其他线程共享一个堆分配。

  1. We have several threads running. With stack allocation, they are allocating in their own stack. With heap allocation, they are allocating from a heap shared with other threads.

较大的尺寸分配。

大小不同,每次分配的(虽然我种子随机发生器,使试验更具有确定性)。这使得堆碎片更可能发生,使得堆分配不是每次都用相同的分配效率较低。

Different sizes allocated each time (though I seeded the random generator to make the tests more deterministic). This makes heap fragmentation more likely to happen, making heap allocation less efficient than with identical allocations each time.

除了这一点,这也是值得一提的是, stackalloc 常常被用来作为替代使用固定引脚在堆上的数组。钢钉阵是坏的堆性能(不只是为code外,还使用了同一个堆其它线程),所以对性能的影响会更大然后,如果所要求的内存将是用于任何合理的长度时间。

As well as this, it's also worth noting that stackalloc would often be used as an alternative to using fixed to pin an array on the heap. Pinning arrays is bad for heap performance (not just for that code, but also for other threads using the same heap), so the performance impact would be even greater then, if the claimed memory would be in use for any reasonable length of time.

虽然我的code说明的情况下 stackalloc 给人以性能优势,在这个问题可能是由更接近大多数情况下,有人可能会急切地优化使用它。希望这两件code一起显示,整个 stackalloc 可以增强,它也伤害了性能提升不少了。

While my code demonstrates a case where stackalloc gives a performance benefit, that in the question is probably closer to most cases where someone might eagerly "optimise" by using it. Hopefully the two pieces of code together show that whole stackalloc can give a boost, it can also hurt performance a lot too.

通常情况下,你应该甚至不考虑 stackalloc ,除非你将需要使用固定内存反正与非托管code相互作用,并应考虑替代固定,而不是替代常规堆分配。使用在这种情况下,仍然需要谨慎,深思熟虑,然后再开始,和配置完成之后。

Generally, you shouldn't even consider stackalloc unless you are going to need to use pinned memory for interacting with unmanaged code anyway, and it should be considered an alternative to fixed rather than an alternative to general heap allocation. Use in this case still requires caution, forethought before you start, and profiling after you finish.

使用在其他情况下,可以给一个好处,但它应该是远了性能改进列表,你会尝试。

Use in other cases could give a benefit, but it should be far down the list of performance improvements you would try.

编辑:

要回答这个问题的第一部分。 Stackalloc是象你所说的概念了。它获得堆栈内存块,然后返回一个指向该块。它不检查的存储器将适合作为这样,而是如果它试图获得存储器进栈的端 - 它是由.NET线程上建立保护 - 那么这将导致操作系统到一个exceptioin返回到运行时的,它再变成一个.NET托管异常。许多同样的情况,如果你只分配一个字节与无限递归的方法 - 除非呼吁得到了优化,以避免堆栈分配(有时可能),那么一个字节将最终加起来足以引发堆栈溢出异常。

To answer part 1 of the question. Stackalloc is conceptually much as you describe. It obtains a chunk of the stack memory, and then returns a pointer to that chunk. It doesn't check the memory will fit as such, but rather if it attempts to obtain memory into the end of the stack - which is protected by .NET on thread creation - then this will cause the OS to return an exceptioin to the runtime, which it then turns into a .NET managed exception. Much the same happens if you just allocate a single byte in a method with infinite recursion - unless the call got optimised to avoid that stack allocation (sometimes possible), then a single byte will eventually add up to enough to trigger the stack overflow exception.

这篇关于营; .NET:stackalloc的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆