我正在编写在Windows Server 2016上运行的.NET
应用程序,该应用程序会在一堆大文件中获取http。由于您可以并行下载它们,因此大大加快了下载过程。不幸的是,一旦将它们下载,将它们花费很长时间才能将它们重新组合在一起。
需要合并2-4k个文件。将在其上运行的服务器具有充足的内存,接近800GB
。我认为使用MemoryStream
来存储下载的片段,直到它们可以顺序写入磁盘为止是很有意义的。但我只能消耗大约2.5GB
的内存在出现System.OutOfMemoryException
错误之前。该服务器有数百GB可用空间,我不知道如何使用它们。
答案 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可以在后台将数据存储到磁盘中(刷新),因此您不必这样做,并且应具有出色的性能。