I have attached the Visual Studio sources for a command-line app that demonstrates the reported problem.
You'll see the app builds to target x86 rather than x64 or Any CPU. This is to reflect the fact that the customers reporting this issue are still using 32-bit machines, and we cannot insist they move to x64.
The built app runs in two steps:
Step 1 - Call a function named ConsumeMemory that constructs two List collections using many 100KB MemoryStreams, It adds each even-numbered MemoryStream to one List, and each odd-numbered MemoryStream to the other List. But it only actually returns one of the Lists, so the Garbage Collector should free up the other List. This is my attempt at deliberately fragmenting the LOH (Large Object Heap).
Key point is that after ConsumeMemory returns, there is still lots of memory available, but the largest contiguous chunk is only 100KB big.
Step 2 - Load the large msg file. The msg I provided might look a bit contrived, but it is similar to the files our customers expect to be able to print. Our customers are solicitors, and they print multi-page pdf files made from scans of paper documents and large Word documents and the like.
How to demonstrate the problem
1. Run the app with no command line options. It will attempt to allocate 20000 x 100KB MemoryStreams, which will cause an exception message:
ConsumeMemory requested 20000 100KB chunks. Allocation failure occurred when idx = 18871
On my machine the allocation failed trying to allocate MemoryStream number 18871. YMMV
2. Run the exe again, but specify a number on the command line. Use a slightly reduced chunk count from the first time around, e.g. AsposeTestApp 18800. When I did this I got an exception:
Exception of type 'System.OutOfMemoryException' was thrown.
at System.IO.MemoryStream..ctor(Int32 capacity)
at #=q0O7zzHnm8HpMXWxOGM7N5F2yF0s7heAiNWzl0$t9b5MhWBLD2oTJZJtS0AKOwAaq.#=qsFJfxFNgjyAsqjNaNyhTKQ==(UInt32 #=qd0lAJycU69Lb_GnugvnJeQ==, Int32 #=q3ahYqqrsj91BmlmTpFlxlw==, Boolean #=qoYNI3d_i4_JwhgDK1y3dng==)
at #=q0O7zzHnm8HpMXWxOGM7N5F2yF0s7heAiNWzl0$t9b5MhWBLD2oTJZJtS0AKOwAaq.#=qCD3HyoO3c1W_G4TPEFPovQ==(Stream #=qs89w56tWTZS_dmT1MHeNCQ==)
at #=q0O7zzHnm8HpMXWxOGM7N5F2yF0s7heAiNWzl0$t9b5MhWBLD2oTJZJtS0AKOwAaq..ctor(Stream #=qs89w56tWTZS_dmT1MHeNCQ==)
at Aspose.Email.Outlook.MapiMessageReader..ctor(Stream stream)
at Aspose.Email.Mail.MailMessage.#=qmDOctRE$xFFKVn8a4_am3w==(Stream #=qs89w56tWTZS_dmT1MHeNCQ==, MsgLoadOptions #=qHgmybkduHS8HPZm$NSK97w==)
at Aspose.Email.Mail.MailMessage.#=qHf2Oi8A8TQbb0w37rB0PjzdikgVuhb$j4cf3Eqa48fY=(Stream #=qs89w56tWTZS_dmT1MHeNCQ==, LoadOptions #=qHgmybkduHS8HPZm$NSK97w==)
at Aspose.Email.Mail.MailMessage.Load(Stream stream)
at Aspose.Email.Mail.MailMessage.Load(String fileName)
at AsposeTestApp.Program.Main(String args) in c:\Development\Sandbox\AsposeTestApp\Program.cs:line 32
and you can see the exception is due to MemoryStream.
Although I cannot debug the aspose code named in the stack trace, the MemoryStream will fail because it is trying to allocate a contiguous byte array larger than 100KB and there are none in the LOH because it has been fragmented.
This would not be a problem if a different Stream type was used instead, one that did its allocations from the SOH and stitched multiple small arrays together to behave like a larger one.