单个.net进程的内存限制为大约2.5 GB

时间:2018-11-07 15:55:30

标签: c# .net windows memory 64-bit

我正在编写在Windows Server 2016上运行的.NET应用程序,该应用程序会在一堆大文件中获取http。由于您可以并行下载它们,因此大大加快了下载过程。不幸的是,一旦将它们下载,将它们花费很长时间才能将它们重新组合在一起。

需要合并2-4k个文件。将在其上运行的服务器具有充足的内存,接近800GB。我认为使用MemoryStream来存储下载的片段,直到它们可以顺序写入磁盘为止是很有意义的。我只能消耗大约2.5GB的内存在出现System.OutOfMemoryException错误之前。该服务器有数百GB可用空间,我不知道如何使用它们。

4 个答案:

答案 0 :(得分:4)

MemoryStreams是围绕字节数组构建的。 Arrays cannot be larger than 2GB currently.

  

System.Array的当前实现将Int32用于其所有内部计数器等,因此,理论上最大的元素数是Int32.MaxValue。

     

Microsoft CLR还设置了每对象最大2GB大小限制

当您尝试将内容放在单个MemoryStream中时,基础数组变得太大,因此是例外。

尝试单独存储片段,并在准备就绪时将它们直接写到FileStream(或您使用的任何东西)上,而无需首先将它们全部串联为一个对象。

答案 1 :(得分:0)

根据MemoryStream class的源代码,您将不能在该类的一个实例中存储超过2 GB的数据。 原因是流的最大长度设置为Int32.MaxValue,而array的最大索引设置为0x0x7FFFFFC7,即十进制2.147.783.591(= 2 GB)

片段MemoryStream

private const int MemStreamMaxLength = Int32.MaxValue;

代码段数组

// We impose limits on maximum array lenght in each dimension to allow efficient 
// implementation of advanced range check elimination in future.
// Keep in sync with vm\gcscan.cpp and HashHelpers.MaxPrimeArrayLength.
// The constants are defined in this method: inline SIZE_T MaxArrayLength(SIZE_T componentSize) from gcscan
// We have different max sizes for arrays with elements of size 1 for backwards compatibility
internal const int MaxArrayLength = 0X7FEFFFFF;
internal const int MaxByteArrayLength = 0x7FFFFFC7;

问题More than 2GB of managed memory早已在Microsoft论坛上进行了讨论,并在其中引用了有关BigArray, getting around the 2GB array size limit的博客文章。

更新

我建议使用以下代码,该代码应能够在x64构建上分配超过4 GB的空间,但在x86构建上分配不到4 GB的空间

private static void Main(string[] args)
{
    List<byte[]> data = new List<byte[]>();
    Random random = new Random();

    while (true)
    {
        try
        {
            var tmpArray = new byte[1024 * 1024];
            random.NextBytes(tmpArray);
            data.Add(tmpArray);
            Console.WriteLine($"{data.Count} MB allocated");
        }
        catch
        {
            Console.WriteLine("Further allocation failed.");
        }
    }
}

答案 2 :(得分:0)

正如已经指出的那样,这里的主要问题是$JSONConvert = $jsonContent | ConvertTo-Json -Depth 4 $JSONEncode = [System.Text.UTF8Encoding]::new($false) [System.IO.File]::WriteAllLines('C:\P3\myFile.JSON',$JSONConvert ,$JSONEncode) Set-AzureStorageBlobContent -Context $storageContext -Container "myContainer" -File "myFile.JSON" -Properties @{"ContentEncoding" = "UTF-8"} -Force MemoryStream支持的性质,byte[]具有固定的上限。

已注意到使用替代Stream实现的选项。另一种选择是研究“管道”,即新的IO API。 “流水线”基于不连续的内存,这意味着不需要使用单个连续的缓冲区。管道库将根据需要分配多个平板,您的代码可以处理这些平板。我已经广泛地写了这个话题。第1部分is here。第3部分可能最关注代码。

答案 3 :(得分:-1)

仅需确认我已理解您的问题:您正在下载多个并行块中的单个非常大的文件,并且您知道最终文件有多大?如果您不这样做的话,这确实会更加复杂,但是仍然可以做到。

最好的选择可能是使用MemoryMappedFile(MMF)。您将要做的是通过MMF创建目标文件。每个线程将创建该文件的视图访问器并并行写入。最后,关闭MMF。本质上,这为您提供了MemoryStreams所需的行为,但Windows通过磁盘备份了文件。这种方法的好处之一是Windows可以在后台将数据存储到磁盘中(刷新),因此您不必这样做,并且应具有出色的性能。