Class: Pdfrb::Task::MemoryProfile

Inherits:
Object
  • Object
show all
Defined in:
lib/pdfrb/task/memory_profile.rb

Overview

Memory profiling using ObjectSpace. Reports total object allocations, memory footprint, and identifies potential leaks for large documents.

Usage:

Pdfrb::Task::MemoryProfile.profile(pdf_bytes)
Pdfrb::Task::MemoryProfile.compare(pdf_a, pdf_b)

Defined Under Namespace

Classes: Snapshot

Class Method Summary collapse

Class Method Details

.diff_types(before, after) ⇒ Object



73
74
75
76
77
78
79
80
# File 'lib/pdfrb/task/memory_profile.rb', line 73

def diff_types(before, after)
  result = {}
  (after.keys | before.keys).each do |type|
    delta = (after[type] || 0) - (before[type] || 0)
    result[type] = delta if delta != 0
  end
  result.sort_by { |_, v| -v }.to_h
end

.object_snapshotObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/pdfrb/task/memory_profile.rb', line 40

def object_snapshot
  by_type = Hash.new(0)
  total_bytes = 0

  ObjectSpace.each_object do |obj|
    next if obj.is_a?(Class) || obj.is_a?(Module)

    type_label = type_label_for(obj)
    by_type[type_label] += 1
    total_bytes += ObjectSpace.memsize_of(obj)
  end

  Snapshot.new(
    total_objects: ObjectSpace.count_objects[:TOTAL],
    total_bytes: total_bytes,
    by_type: by_type
  )
rescue StandardError
  Snapshot.new(total_objects: 0, total_bytes: 0, by_type: {})
end

.profile(pdf_bytes) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/pdfrb/task/memory_profile.rb', line 19

def profile(pdf_bytes)
  GC.start
  GC.disable

  baseline = object_snapshot

  doc = Pdfrb::Document.new(io: StringIO.new(pdf_bytes.dup))
  doc.each_indirect_object { |_obj| nil }
  doc.pages.each { |_page| nil }

  after = object_snapshot

  GC.enable

  Snapshot.new(
    total_objects: after.total_objects - baseline.total_objects,
    total_bytes: after.total_bytes - baseline.total_bytes,
    by_type: diff_types(baseline.by_type, after.by_type)
  )
end

.type_label_for(obj) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/pdfrb/task/memory_profile.rb', line 61

def type_label_for(obj)
  case obj
  when String then "String"
  when Hash then "Hash"
  when Array then "Array"
  when Pdfrb::Model::Object, Pdfrb::Model::Cos::Dictionary then "Pdfrb::Model"
  when Pdfrb::Model::Reference then "Reference"
  when Pdfrb::Model::PdfArray then "PdfArray"
  else obj.class.name || obj.class.to_s
  end
end