Home > Net >  Using memory stream is throwing out of memory exeption
Using memory stream is throwing out of memory exeption

Time:01-21

I have a requirement where I need to encrypt file of size 1-2 GB in azure function. In am using PGP core library to encrypt file in memory. The below code is throwing out of memory exception if file size is above 700 MB. Note:- I am using azure function. Scaling up of App service plan didn't help.

I there any alternate of Memory stream that I can use. After encryption , I am uploading file into blob storage.

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, outputStream);
            

CodePudding user response:

MemoryStream uses a byte[] internally, and any byte[] is going to get a bit brittle as it gets around/above 1GiB (although in theory a byte[] can be nearly 2 GiB, in reality this isn't a good idea, and is rarely seen).

Frankly, MemoryStream simply isn't a good choice here; I'd probably suggest using a temporary file instead, and use a FileStream. This doesn't attempt to keep everything in memory at once, and is more reliable at large sizes. Alternatively: avoid ever needing all the data at once completely, by performing the encryption in a pass-thru streaming way.

CodePudding user response:

MemoryStream is a Stream wrapper over a byte[]` buffer. Every time that buffer is full, a new one with double the size is allocated and the data is copied. This eventually uses double the final buffer size (4GB for a 2GB file) but worse, it results in such memory fragmentation that eventually the memory allocator can't find a new contiguous memory block to allocate. That's when you get an OOM.

While you could avoid OOM errors by specifying a capacity in the constructor, storing 2GB in memory before even starting to write it is very wasteful. With a real FileStream the encrypted bytes would be written out as soon as they were available.

Azure Functions allow temporary storage. This means you can create a temporary file, open a stream on it and use it for encryption.

var tempPath=Path.GetTempFileName();
try
{
    using (var outputStream=File.Open(tempPath))
    {

        await pgp.EncryptStreamAsync(streamToEncrypt, outputStream);
        ...
    }
}
finally
{
    File.Delete(tempPath);
}
  •  Tags:  
  • Related