1

I am using the pdf stamper to encrypt the pdf with password. our requirement is to do 50 pdf files in parallel and size of each file can be upto 300 MB.

If I run the code and to encrypt the 50 files in parallel 2-3 times I get out of memory exception. Can you please help figureout what i am doing wrong ?

I even tried to use GC.Collect and GC.WaitForPendingFinalizers, but issue still exists.

I have created a test case below where i copy same file 50 times and execute them in parallel.

Thanks for your help.

My code is as follows :

private void button1_Click(object sender, EventArgs e)
{
    try
    {
        int[] nums = Enumerable.Range(0, 50).ToArray();
        string pdfTestDir = @"C:\ztemp\pdfTest";
        string originalFile = @"C:\Ztemp\Original.pdf";
        string newFile = @"C:\Ztemp\pdfTest\NewPdf_";
        if (Directory.Exists(pdfTestDir)) { Directory.Delete(pdfTestDir, true); }
        Directory.CreateDirectory(pdfTestDir);
        if (Directory.Exists(pdfTestDir))
        {
            Parallel.ForEach<int>(nums, t =>
            {
                try
                {
                    int userCopy = t + 1;

                    string newFilePath = newFile + userCopy.ToString() + ".pdf";
                    System.IO.File.Copy(originalFile, newFilePath);

                    ProtectPdf(newFilePath);
                }
                catch (Exception ex)
                {
                    throw ex;
                }


            });
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        MessageBox.Show("Done");
    }
    catch (Exception exc)
    {
        MessageBox.Show(exc.Message);
    }
}


public void ProtectPdf(string file)
{
    try
    {
        FileInfo fileInfo = new FileInfo(file);
        string password = "password";
        // Default strength; 128
        var strength = PdfWriter.ENCRYPTION_AES_128;
        // Get permission; default is PdfWriter.ALLOW_SCREENREADER
        var permissions = PdfWriter.ALLOW_SCREENREADERS; 
        var tempInfo = new FileInfo(fileInfo.FullName.ToLower().Replace(".pdf", ".enrypted.pdf"));
        if (tempInfo.Exists)
        {
            tempInfo.Delete();
        }
        var sInFilePath = fileInfo.FullName;
        var sOutFilePath = tempInfo.FullName;

        using (var existingFileStream = new FileStream(sInFilePath, FileMode.Open))
        using (var newFileStream = new FileStream(sOutFilePath, FileMode.Create))
        {
            // Open existing PDF
            var pdfReader = new PdfReader(existingFileStream);

            // PdfStamper, which will create
            var stamper = new PdfStamper(pdfReader, newFileStream);
            try
            {
                stamper.SetEncryption(strength, password, password, permissions);
                stamper.SetFullCompression();

                stamper.Close();
                stamper.Dispose();
                pdfReader.Close();
                pdfReader.Dispose();
                newFileStream.Close();
                newFileStream.Dispose();
                existingFileStream.Close();
                existingFileStream.Dispose();

            }
            catch (Exception ex)
            {
                stamper.Close();
                stamper.Dispose();
                pdfReader.Close();
                pdfReader.Dispose();
                throw ex;
            }
        }
        fileInfo.Delete();
        tempInfo.MoveTo(sInFilePath);
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
    catch (Exception ex)
    {
        throw ex;
    }

}
Chris Haas
  • 53,986
  • 12
  • 141
  • 274
  • 2
    _"what am I doing wrong?"_ - you're using too much memory. – CodeCaster Oct 14 '15 at 10:35
  • I think there is some memory leakage issue. running 50 in parallel is the requirement. as we need generate hundreds of pdf for our client and is very time bound. – user3889275 Oct 14 '15 at 10:40
  • 1
    There is no memory leak. Your requirements go against the laws of physics. You need more memory, more processes or more machines. – CodeCaster Oct 14 '15 at 10:41
  • Maybe you could do this in batches of 4 - rather than all 50 at the same time? Since I'm guessing you don't have a 50 core processor... and I doubt your drive is going to handle writing that amount of data in one go... Plus as CodeCaster mentions that 300MB multiplied by 50 into memory in one go is going to be causing problems too... – Chris Nevill Oct 14 '15 at 11:00
  • Having 4 in batch is very low and not an option as will take lot of time, as we not only do the password but also generate the pdf document , which itself takes a long time. Our app server has 64 virtual core processor and about 256GB of Memory, but I agree all may be not available for my .net process. – user3889275 Oct 14 '15 at 11:34
  • Calling `Close()` and `Dispose()` on your MemoryStreams are not necessary since they're wrapped in `using { }`. `PdfStamper` should also be in a `using { }` like here (see kuujinbo's answer): http://stackoverflow.com/questions/27188593/getting-pdfstamper-to-work-with-memorystreams-c-itextsharp – Rick Burns Oct 14 '15 at 12:50
  • 1
    Consider opening the `PdfReader` in partial mode. This will make it load only what is required at the moment, not the whole PDF. Cf. the experiences shown in [this answer](http://stackoverflow.com/a/30479556/1729265). – mkl Oct 14 '15 at 12:52
  • 1
    Unrelated to your problem, but never [`throw ex`](http://stackoverflow.com/a/2999314/231316) – Chris Haas Oct 14 '15 at 13:32
  • Hi Mkl, plesae advice how to open pdfreader in partial mode? Thanks. – user3889275 Oct 26 '15 at 12:55

0 Answers0