We are running into out-of-memory (OOM) exceptions when we load multiple large (8 MB+) images into Aspose.Pdf documents in our x32 .NET application. As in the code below, we create intermediate Aspose Documents that each include a single image and combine the documents into a destination document. Based on our production application, PDF creation succeeds for a number of documents and it fails indefinitely once an out-of-memory exception occurs. The code below closely mirrors our actual application. OOM exceptions can be readily reproduced by running the test code with >10 iterations and >8 MB image files. As in our production application, the test application is unsalvageable after an OOM exception occurs. In the test app, selecting to continue after an OOM exception occurs, is immediately followed by another OOM exception - the memory is not being cleared. The test application performs without issue when compiled x64, but that is not an option for us. In your Java implementation it appears that there’s a MemoryCleaner class. Does a similar class exist in Aspose .NET? Is there another method or technique that you recommend for clearing the memory after each iteration so that our application does not degenerate until it fails?
Thanks in advance for any help.
Test app:
using Aspose.Pdf;
using System;
using System.Collections.Generic;
using System.IO;
namespace TestAspose
{
// Command line example:
// "C:\\Temp\\rome17MB.JPG" 20
class Program
{
static void Main(string[] args)
{
License license = new License();
license.SetLicense("Aspose.Pdf.lic");
int totalBeforeFailure = 0;
while (true)
{
Document destinationDocument = new Document();
int nImages = 0;
string imagePath = string.Empty;
if (args.Length != 2)
{
Console.WriteLine("Number of input arguments must be 2. Path to image and number of images.");
}
else
{
imagePath = args[0];
nImages = Convert.ToInt32(args[1]);
Console.WriteLine($"Path = {imagePath}. Count = {nImages}");
}
List<ByteAndDocument> imageList = null;
int index = 0;
try
{
imageList = new List<ByteAndDocument>();
for (; index < nImages; index++)
{
var byteAndStream = new ByteAndDocument();
System.Drawing.Image img = System.Drawing.Image.FromFile(imagePath);
using (MemoryStream memoryStream = new MemoryStream())
{
byteAndStream.Bytes = File.ReadAllBytes(imagePath);
Console.WriteLine($"Added file {index + 1} to byte array");
}
imageList.Add(byteAndStream);
}
// Create Aspose documents for each image
index = 0;
foreach (var image in imageList)
{
ByteToDocument(image);
index++;
Console.WriteLine($"Added byte array {index} to Aspose document");
}
// Add each image to the destination document
index = 0;
foreach (var image in imageList)
{
destinationDocument.Pages.Add(image.Document.Pages);
index++;
totalBeforeFailure++;
Console.WriteLine($"Adding sub (image) Aspose document {index} to destination document");
}
Console.WriteLine($"Finished creating {index} image->Aspose document conversions for this iteration. {totalBeforeFailure} total successful image->Aspose document conversions!\n\n");
}
catch (Exception e)
{
Console.WriteLine($"Total number of successful image->Aspose document conversions before failure {totalBeforeFailure}. Exception: {e}");
totalBeforeFailure = 0;
Console.WriteLine("\nContinue (y/n)?: ");
var key = Console.ReadKey();
if (key.KeyChar.ToString().ToUpper() == "N")
{
break;
}
}
finally
{
foreach (var img in imageList)
{
if (img.Document != null)
{
img.Document.Dispose();
img.Document = null;
}
img.Bytes = null;
}
imageList.Clear();
imageList = null;
destinationDocument.Dispose();
destinationDocument = null;
}
}
}
private static void ByteToDocument(ByteAndDocument byteAndStream)
{
byteAndStream.Document = new Document();
byteAndStream.Document.Pages.Add();
Page page = byteAndStream.Document.Pages[1];
MemoryStream memoryStream = new MemoryStream(byteAndStream.Bytes);
page.Resources.Images.Add(memoryStream);
}
public class ByteAndDocument
{
public byte[] Bytes { get; set; }
public Document Document { get; set; }
public ByteAndDocument()
{
Bytes = null;
Document = null;
}
}
}
}