Browse Source

Memory optimization: dispose native objects when an exception is thrown during generation

Marcin Ziąbek 9 months ago
parent
commit
242521de6b
1 changed files with 47 additions and 36 deletions
  1. 47 36
      Source/QuestPDF/Drawing/DocumentGenerator.cs

+ 47 - 36
Source/QuestPDF/Drawing/DocumentGenerator.cs

@@ -153,15 +153,20 @@ namespace QuestPDF.Drawing
             if (canvas is CompanionCanvas)
                 content.VisitChildren(x => x.CreateProxy(y => new LayoutProxy(y)));
             
-            var pageContext = new PageContext();
-            RenderPass(pageContext, new FreeCanvas(), content);
-            pageContext.ProceedToNextRenderingPhase();
-            RenderPass(pageContext, canvas, content);
-            
-            if (canvas is CompanionCanvas companionCanvas)
-                companionCanvas.Hierarchy = content.ExtractHierarchy();
+            try
+            {
+                var pageContext = new PageContext();
+                RenderPass(pageContext, new FreeCanvas(), content);
+                pageContext.ProceedToNextRenderingPhase();
+                RenderPass(pageContext, canvas, content);
             
-            content.ReleaseDisposableChildren();
+                if (canvas is CompanionCanvas companionCanvas)
+                    companionCanvas.Hierarchy = content.ExtractHierarchy();
+            }
+            finally
+            {
+                content.ReleaseDisposableChildren();
+            }
         }
         
         private static void RenderMergedDocument<TCanvas>(TCanvas canvas, MergedDocument document, DocumentSettings settings)
@@ -177,40 +182,48 @@ namespace QuestPDF.Drawing
                     Content = ConfigureContent(document.Documents[index], settings, useOriginalImages)
                 })
                 .ToList();
-
-            if (document.PageNumberStrategy == MergedDocumentPageNumberStrategy.Continuous)
+            
+            try
             {
-                var documentPageContext = new PageContext();
-
-                foreach (var documentPart in documentParts)
+                if (document.PageNumberStrategy == MergedDocumentPageNumberStrategy.Continuous)
                 {
-                    documentPageContext.SetDocumentId(documentPart.DocumentId);
-                    RenderPass(documentPageContext, new FreeCanvas(), documentPart.Content);
-                }
+                    var documentPageContext = new PageContext();
+
+                    foreach (var documentPart in documentParts)
+                    {
+                        documentPageContext.SetDocumentId(documentPart.DocumentId);
+                        RenderPass(documentPageContext, new FreeCanvas(), documentPart.Content);
+                    }
                 
-                documentPageContext.ProceedToNextRenderingPhase();
+                    documentPageContext.ProceedToNextRenderingPhase();
 
-                foreach (var documentPart in documentParts)
-                {
-                    documentPageContext.SetDocumentId(documentPart.DocumentId);
-                    RenderPass(documentPageContext, canvas, documentPart.Content);
-                    documentPart.Content.ReleaseDisposableChildren();
+                    foreach (var documentPart in documentParts)
+                    {
+                        documentPageContext.SetDocumentId(documentPart.DocumentId);
+                        RenderPass(documentPageContext, canvas, documentPart.Content);
+                        documentPart.Content.ReleaseDisposableChildren();
+                    }
                 }
-            }
-            else
-            {
-                foreach (var documentPart in documentParts)
+                else
                 {
-                    var pageContext = new PageContext();
-                    pageContext.SetDocumentId(documentPart.DocumentId);
+                    foreach (var documentPart in documentParts)
+                    {
+                        var pageContext = new PageContext();
+                        pageContext.SetDocumentId(documentPart.DocumentId);
                     
-                    RenderPass(pageContext, new FreeCanvas(), documentPart.Content);
-                    pageContext.ProceedToNextRenderingPhase();
-                    RenderPass(pageContext, canvas, documentPart.Content);
+                        RenderPass(pageContext, new FreeCanvas(), documentPart.Content);
+                        pageContext.ProceedToNextRenderingPhase();
+                        RenderPass(pageContext, canvas, documentPart.Content);
                     
-                    documentPart.Content.ReleaseDisposableChildren();
+                        documentPart.Content.ReleaseDisposableChildren();
+                    }
                 }
             }
+            catch
+            {
+                documentParts.ForEach(x => x.Content.ReleaseDisposableChildren());
+                throw;
+            }
         }
 
         private static Container ConfigureContent(IDocument document, DocumentSettings settings, bool useOriginalImages)
@@ -315,17 +328,15 @@ namespace QuestPDF.Drawing
                         $"To learn more, please analyse the document measurement of the problematic location: {newParagraph}{layoutText}" +
                         $"{LayoutDebugging.LayoutVisualizationLegend}{newParagraph}" +
                         $"This detailed information is generated because you run the application with a debugger attached or with the {debuggingSettingsName} flag set to true. ";
-
-                    throw new DocumentLayoutException(message);
                 }
                 else
                 {
                     message +=
                         $"To further investigate the location of the root cause, please run the application with a debugger attached or set the {debuggingSettingsName} flag to true. " +
                         $"The library will generate additional debugging information such as probable code problem location and detailed layout measurement overview.";
-                    
-                    throw new DocumentLayoutException(message);
                 }
+                
+                throw new DocumentLayoutException(message);
             }
             
             (ICollection<Element> ancestors, TreeNode<OverflowDebuggingProxy> layout) GenerateLayoutExceptionDebuggingInfo()