Skip to content

Memory leak and performance issue #728

@CorvusCorrax

Description

@CorvusCorrax

Generating large file (> 10000 pages) crash node on my system (Linux Fedora 23) :
JavaScript heap out of memory

Here is my test script :

var PDFDocument = require('pdfkit');
var fs = require('fs');
var doc = new PDFDocument();
var v8 = require('v8');
var pageCount = 20000;

var getStats = function(text) {
  var stats = v8.getHeapSpaceStatistics();
  stats.forEach(function(stat) {
    console.log(text + ' ' + stat.space_name + ' available size : ' + stat.space_available_size);
  });
};

doc.pipe(fs.createWriteStream('test.pdf'));

console.time('Pdf generation time');
doc.on('end', function() {
  console.log();
  getStats('Final memory');
  console.log();
  console.timeEnd('Pdf generation time');
});

console.log('Start generating ' + pageCount + ' pages');
getStats('Starting memory');

for (var i = 1; i < pageCount; ++i) {
  for (var y = 0; y < 40; ++y) {
    doc.text('testText', y, y);
  }
  doc.addPage();
  if (i % 4000 === 0) {
    console.log();
    getStats('Page ' + i);
  }
}
doc.end();

And here is the result :

Start generating 20000 pages
Starting memory new_space available size : 775352
Starting memory old_space available size : 122488
Starting memory code_space available size : 231872
Starting memory map_space available size : 450104
Starting memory large_object_space available size : 1472650752

Page 4000 new_space available size : 8944344
Page 4000 old_space available size : 33672632
Page 4000 code_space available size : 1745920
Page 4000 map_space available size : 563520
Page 4000 large_object_space available size : 958758400

Page 8000 new_space available size : 9308184
Page 8000 old_space available size : 65610464
Page 8000 code_space available size : 1249696
Page 8000 map_space available size : 563432
Page 8000 large_object_space available size : 461798912

Page 12000 new_space available size : 1275960
Page 12000 old_space available size : 62591016
Page 12000 code_space available size : 782144
Page 12000 map_space available size : 564048
Page 12000 large_object_space available size : 0

<--- Last few GCs --->

[30138:0x34205a0]   218726 ms: Mark-sweep 1400.9 (1545.8) -> 1400.9 (1541.3) MB, 2200.4 / 0.1 ms  (+ 0.0 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 2201 ms) last resort 
[30138:0x34205a0]   221096 ms: Mark-sweep 1400.9 (1541.3) -> 1400.9 (1541.3) MB, 2368.5 / 0.1 ms  last resort 


<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 0x2313edd29891 <JS Object>
    2: _text [/home/dev/svn/testPdfKit/node_modules/pdfkit/js/mixins/text.js:~33] [pc=0x9b80fbc8006](this=0x3c6fdb4a5a99 <a PDFDocument with map 0x1bebc6d107f9>,text=0x19e7d0cf6569 <String[8]: testText>,x=29,y=29,options=0x38aeea002311 <undefined>,lineCallback=0x69f67fdc639 <JS BoundFunction (BoundTargetFunction 0x3c6fdb4a9e31)>)
    3: /* anonymous */ [/home/dev/svn/testPdfKit/pdfTest.js:~1] [...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node::Abort() [node]
 2: 0x13647ec [node]
 3: v8::Utils::ReportOOMFailure(char const*, bool) [node]
 4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [node]
 5: v8::internal::Factory::NewByteArray(int, v8::internal::PretenureFlag) [node]
 6: v8::internal::SourcePositionTableBuilder::ToSourcePositionTable(v8::internal::Isolate*, v8::internal::Handle<v8::internal::AbstractCode>) [node]
 7: v8::internal::FullCodeGenerator::MakeCode(v8::internal::CompilationInfo*, unsigned long) [node]
 8: v8::internal::FullCodegenCompilationJob::ExecuteJobImpl() [node]
 9: v8::internal::CompilationJob::ExecuteJob() [node]
10: 0xd97d90 [node]
11: 0xd98b28 [node]
12: 0xd98d8f [node]
13: 0xd9ce59 [node]
14: v8::internal::Compiler::Compile(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Compiler::ClearExceptionFlag) [node]
15: v8::internal::Runtime_CompileLazy(int, v8::internal::Object**, v8::internal::Isolate*) [node]
16: 0x9b80f68437d
Abandon (core dumped)

After some analysis, i found out that the writable streams from referencePDF object eats a lot of memory.
Same test result after removing the streams :

Start generating 20000 pages
Starting memory new_space available size : 2121376
Starting memory old_space available size : 600
Starting memory code_space available size : 352
Starting memory map_space available size : 450104
Starting memory large_object_space available size : 1472650752

Page 4000 new_space available size : 2915960
Page 4000 old_space available size : 21162392
Page 4000 code_space available size : 322848
Page 4000 map_space available size : 562200
Page 4000 large_object_space available size : 1162141184

Page 8000 new_space available size : 7767744
Page 8000 old_space available size : 69523024
Page 8000 code_space available size : 0
Page 8000 map_space available size : 562200
Page 8000 large_object_space available size : 877977088

Page 12000 new_space available size : 9225224
Page 12000 old_space available size : 101655856
Page 12000 code_space available size : 0
Page 12000 map_space available size : 562376
Page 12000 large_object_space available size : 589618688

Page 16000 new_space available size : 5595376
Page 16000 old_space available size : 133766616
Page 16000 code_space available size : 0
Page 16000 map_space available size : 562200
Page 16000 large_object_space available size : 301784576

Final memory new_space available size : 4856536
Final memory old_space available size : 569029752
Final memory code_space available size : 154112
Final memory map_space available size : 566336
Final memory large_object_space available size : 22240768

Pdf generation time: 82549.040ms

It seems that large_object_space available memory gets eaten up a lot more slowly and the process also goes faster :
2000 pages with streams :

Start generating 2000 pages
Starting memory new_space available size : 775320
Starting memory old_space available size : 122472
Starting memory code_space available size : 234816
Starting memory map_space available size : 450104
Starting memory large_object_space available size : 1472650752

Final memory new_space available size : 8711240
Final memory old_space available size : 13663000
Final memory code_space available size : 285504
Final memory map_space available size : 561408
Final memory large_object_space available size : 1191419392

Pdf generation time: 5894.804ms

2000 pages without streams :

Start generating 2000 pages
Starting memory new_space available size : 9768096
Starting memory old_space available size : 428104
Starting memory code_space available size : 185024
Starting memory map_space available size : 152
Starting memory large_object_space available size : 1427037696

Final memory new_space available size : 13427376
Final memory old_space available size : 14697760
Final memory code_space available size : 1355936
Final memory map_space available size : 373800
Final memory large_object_space available size : 1289543168

Pdf generation time: 4895.007ms

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions