.NET堆栈内存限制

时间:2012-03-17 11:02:53

标签: .net memory 64-bit stack limit

我正在使用C#,.NET 4.0,64位。我需要在内存中存储5亿个用于计算的“数据点”。我需要决定是将它们创建为struct还是class对象。结构似乎更快。

堆栈是否有内存限制?如果是这样,如何调整。

在堆栈上存储如此多的数据是否会影响系统的整体性能?

(顺便说一句,我知道.NET中的单一对象大小限制,因此正在解决 - 数据将存储在多个集合中。)

4 个答案:

答案 0 :(得分:6)

你问的是错误的问题。如果堆栈大小很重要,那么你做错了。

如果您使用许多数据点,则会将它们放在一个集合中,例如数组。总是在堆上分配数组。结构数组嵌入各个结构并形成连续的内存块。 (如果你有超过2GB,你需要几个数组。)

对于引用类型,数组将只包含引用,并且对象在堆上单独分配。堆分配有大约16个字节的开销,数组中的引用占另外8个字节 由于间接性,你也会得到更糟糕的缓存局部性,并且GC必须做更多工作,以抓取所有这些引用。

我的结论是,如果您有许多小数据点,请将它们作为结构,并将它们放在数组中。

答案 1 :(得分:4)

您要将数据存储在数组中,并且数组始终存储在堆上。因此,无论是否使用结构或类来保存这些数组都无关紧要。您可能希望确保您的数据点是值类型(即结构),以便可以在连续的内存块中有效地分配数据点数组。

堆和堆栈分配内存之间的性能差异最有可能出现在短时间内分配和释放的小对象。对于您描述的大小的长寿命对象,我希望堆栈和堆分配内存之间的性能没有差别。

答案 2 :(得分:1)

可以使用您的数据点类。在这种情况下,内存将在堆上分配。

但是考虑到你正在谈论5亿个数据点,特别是因为你在.NET世界中编程的应用程序的内存限制更受限制,我强烈建议使用某种嵌入式数据库,如sqlite,例。通过这种方式,您可以避免同时将所有数据点都存储在内存中,但只能避免计算所需的数据现在

答案 3 :(得分:1)

令人惊讶的是,似乎没有人试图回答实际问题。

我绝对理解,这是99.9%的时间问的错误问题,但是知道结果仍然很有趣(至少我很好奇)。

测试程序

使用不安全的代码和stackalloc关键字确实很简单。

class Program
{
    static void Main(string[] args)
    {
        for (int i = 100; i < Int32.MaxValue; i+=10)
        {
            StackCheck(i);
            Console.WriteLine($"Successfully allocated {i} bytes on the stack");
        }
    }

    public static unsafe void StackCheck(int size)
    {
        byte* array = stackalloc byte[size];
    }
}

结果

请记住,这是100%的实现细节,并且可能因CLR,CLR版本,操作系统或单个机器而异。在我的实验中,整个.NET Framework 4.7.2和.NET Core 2.1.4都崩溃了,刚好超过1MB标记。有趣的是,运行之间甚至不一致,结果波动了几百个字节。

调整堆栈限制

您不能在现有线程上更改堆栈大小,但可以在新线程上设置堆栈大小

Thread testThread = new Thread(() =>
{
    for (int i = 1000; i < Int32.MaxValue; i+=1000)
    {
        StackCheck(i);
        Console.WriteLine($"Successfully allocated {i} bytes on the stack");
    }
}, 200_000_000);
testThread.Start();
testThread.Join();

显然,创建线程时会分配整个堆栈,如果将其设置得太大,则Thread构造函数将抛出OutOfMemoryException

但是,再次进行此测试主要是为了满足我自己的好奇心,因为其他人表示不要这样做除非您真的很清楚自己在做什么