Azure Function out of memory exception

Viewed 2216

I am reading PDF files from Blob and doing some operation using Azure Function. When PDF size is 1.5GB(or greater) my azure function fails with out of memory exception as soon as it code hit below command.

var ms = new MemoryStream();
log.LogInformation("Converting this File to memorystream : " + blob.Uri);
blob.DownloadToStream(ms);  //Failes HERE.

I tried increasing the plan switched to EP3 (14 GB Memory + 840 ACU). But problem is still same. Do i need to change some other configuration as well? How this could be taken care.

Microsoft.Azure.Storage.StorageException: Exception of type 'System.OutOfMemoryException' was thrown.
 ---> System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at System.IO.MemoryStream.set_Capacity(Int32 value)
   at System.IO.MemoryStream.EnsureCapacity(Int32 value)
   at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at System.IO.MemoryStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Azure.Storage.Core.Util.AsyncStreamCopier`1.StartCopyStreamAsyncHelper(Nullable`1 copyLength, Nullable`1 maxLength, CancellationToken token)
   at Microsoft.Azure.Storage.Core.Util.AsyncStreamCopier`1.StartCopyStreamAsync(Nullable`1 copyLength, Nullable`1 maxLength, CancellationToken cancellationToken)
   at Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteAsync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext, CancellationToken token)
   --- End of inner exception stack trace ---
   at Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteAsync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext, CancellationToken token)
   at Microsoft.Azure.Storage.Core.Executor.Executor.<>c__DisplayClass0_0`1.<ExecuteSync>b__0()
   at Microsoft.Azure.Storage.Core.Util.CommonUtility.RunWithoutSynchronizationContext[T](Func`1 actionToRun)
   at Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext)
   at Microsoft.Azure.Storage.Blob.CloudBlob.DownloadRangeToStream(Stream target, Nullable`1 offset, Nullable`1 length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext)
   at Microsoft.Azure.Storage.Blob.CloudBlob.DownloadToStream(Stream target, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext)
2 Answers

This blog sounds like it has identified the issue - MemoryStream takes an int32 to set its capacity, with no option to use a larger number. I can't quite reconcile the value of int32.MaxValue (2147483647) with the specified size (1.5GiB in bytes is 1610612736 bytes) but it seems close enough to be the culprit. The blog suggests a solution to writing large content to Blob Storage, but I don't see how this could work for your use case.

If you definitely need to use MemoryStream to fulfil the needs of the library you are using, processing files this large will not be possible.

I am reading CSVs, so not totally sure this is directly applicable. However, I tried to do what you are doing there at first, pulling the whole blob in and had this issue. I was able to get significantly more info through our process by using something like this:

public async Task<string> ReadCsvRowRawAsync()
{
   string currentRowRaw = await Reader.ReadLineAsync();
   if (Reader.EndOfStream)
   {
       EndOfStream = true;
   }
   return currentRowRaw;
}

Going line by line allows only a small segment to be stored in memory. I still get issues, but only on the largest of files.

Related