使用内存流会抛出内存异常
Using memory stream is throwing out of memory exeption
我有一个要求,我需要在 azure 函数中加密大小为 1-2 GB 的文件。我正在使用 PGP 核心库来加密内存中的文件。如果文件大小超过 700 MB,下面的代码会抛出内存不足异常。注意:- 我正在使用 azure 函数。扩大应用服务计划没有帮助。
我可以使用任何替代的内存流。加密后,我正在将文件上传到 blob 存储中。
var privateKeyEncoded = Encoding.UTF8.GetString(Convert.FromBase64String(_options.PGPKeys.PublicKey));
using Stream privateKeyStream = StringToStreamUtility.GenerateStreamFromString(privateKeyEncoded);
privateKeyStream.Position = 0;
var encryptionKeys = new EncryptionKeys(privateKeyStream);
var pgp = new PGP(encryptionKeys);
//encrypt stream
var encryptStream = new MemoryStream();
await pgp.EncryptStreamAsync(streamToEncrypt, encryptStream );
MemoryStream
在内部使用 byte[]
,任何 byte[]
都会变得有点脆弱,因为它会变得 around/above 1GiB(尽管理论上 byte[]
可以接近 2 GiB,实际上这不是一个好主意,而且很少见)。
坦率地说,MemoryStream
在这里并不是一个好的选择;我可能会建议改用临时文件,并使用 FileStream
。这不会试图一次将所有内容保存在内存中,并且在大尺寸时更可靠。或者:通过以直通流方式执行加密,避免一次完全需要所有数据。
MemoryStream 是对 byte[]` 缓冲区的 Stream 包装器。每次缓冲区满时,都会分配一个双倍大小的新缓冲区并复制数据。这最终使用了最终缓冲区大小的两倍(4GB 用于 2GB 文件),但更糟糕的是,它导致内存碎片,最终内存分配器无法找到新的连续内存块来分配。那就是你得到 OOM 的时候。
虽然您可以通过在构造函数中指定容量来避免 OOM 错误,但在开始写入之前就在内存中存储 2GB 是非常浪费的。使用真正的 FileStream,加密的字节将在可用时立即写出。
Azure Functions 允许临时存储。这意味着您可以创建一个临时文件,在其上打开流并将其用于加密。
var tempPath=Path.GetTempFileName();
try
{
using (var outputStream=File.Open(tempPath))
{
await pgp.EncryptStreamAsync(streamToEncrypt, outputStream);
...
}
}
finally
{
File.Delete(tempPath);
}
我有一个要求,我需要在 azure 函数中加密大小为 1-2 GB 的文件。我正在使用 PGP 核心库来加密内存中的文件。如果文件大小超过 700 MB,下面的代码会抛出内存不足异常。注意:- 我正在使用 azure 函数。扩大应用服务计划没有帮助。
我可以使用任何替代的内存流。加密后,我正在将文件上传到 blob 存储中。
var privateKeyEncoded = Encoding.UTF8.GetString(Convert.FromBase64String(_options.PGPKeys.PublicKey));
using Stream privateKeyStream = StringToStreamUtility.GenerateStreamFromString(privateKeyEncoded);
privateKeyStream.Position = 0;
var encryptionKeys = new EncryptionKeys(privateKeyStream);
var pgp = new PGP(encryptionKeys);
//encrypt stream
var encryptStream = new MemoryStream();
await pgp.EncryptStreamAsync(streamToEncrypt, encryptStream );
MemoryStream
在内部使用 byte[]
,任何 byte[]
都会变得有点脆弱,因为它会变得 around/above 1GiB(尽管理论上 byte[]
可以接近 2 GiB,实际上这不是一个好主意,而且很少见)。
坦率地说,MemoryStream
在这里并不是一个好的选择;我可能会建议改用临时文件,并使用 FileStream
。这不会试图一次将所有内容保存在内存中,并且在大尺寸时更可靠。或者:通过以直通流方式执行加密,避免一次完全需要所有数据。
MemoryStream 是对 byte[]` 缓冲区的 Stream 包装器。每次缓冲区满时,都会分配一个双倍大小的新缓冲区并复制数据。这最终使用了最终缓冲区大小的两倍(4GB 用于 2GB 文件),但更糟糕的是,它导致内存碎片,最终内存分配器无法找到新的连续内存块来分配。那就是你得到 OOM 的时候。
虽然您可以通过在构造函数中指定容量来避免 OOM 错误,但在开始写入之前就在内存中存储 2GB 是非常浪费的。使用真正的 FileStream,加密的字节将在可用时立即写出。
Azure Functions 允许临时存储。这意味着您可以创建一个临时文件,在其上打开流并将其用于加密。
var tempPath=Path.GetTempFileName();
try
{
using (var outputStream=File.Open(tempPath))
{
await pgp.EncryptStreamAsync(streamToEncrypt, outputStream);
...
}
}
finally
{
File.Delete(tempPath);
}