Project

General

Profile

Actions

Feature #44396

open

Reduce memory usage by not loading rbpdf until a PDF is generated

Added by Go MAEDA about 12 hours ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
Performance
Resolution:

Description

Redmine loads the rbpdf gem at every boot, even though it is only needed for PDF export. This patch defers loading it until a PDF is actually generated. In my measurements, this reduced the median RSS by about 12 MB, from 217.8 MB to 205.9 MB. Processes that do not export PDFs can therefore avoid loading rbpdf and its dependencies for their whole lifetime.

The first patch fixes the existing RuboCop offenses in lib/redmine/export/pdf.rb so that moving ITCPDF in the second patch does not require updating .rubocop_todo.yml.

The second patch makes the following changes:

1. Adds require: false to gem 'rbpdf' so that Bundler does not load rbpdf at boot.
2. Moves the ITCPDF class to a new file, lib/redmine/export/pdf/itcpdf.rb, where rbpdf is explicitly required. RDMPdfEncoding stays in lib/redmine/export/pdf.rb because it does not depend on rbpdf.
3. Excludes the new file from eager loading with loader.do_not_eager_load. The file remains autoloadable, so it and rbpdf are loaded when Redmine::Export::PDF::ITCPDF is first referenced.

I measured the effect by booting a production environment and reading the RSS of the process:

for i in 1 2 3 4 5; do bin/rails r -e production 'GC.start; puts "RSS=#{`ps -o rss= -p #{$$}`.to_i}KB rbpdf=#{$LOADED_FEATURES.grep(%r{/rbpdf-}).any?}"'; done

macOS 15 (arm64), Ruby 3.4.8, SQLite3, no plugins, assets already precompiled, 5 runs each:

RSS median RSS range rbpdf loaded
trunk 217.8 MB 212.5–218.7 MB yes
patched 205.9 MB 205.5–208.5 MB no

With the patch, rbpdf, rbpdf-font, and htmlentities are no longer loaded at boot.

With a preforking server such as Puma in cluster mode, loading rbpdf in the master process allows its memory to be shared with workers through copy-on-write. An installation that exports PDFs often can keep the old behavior by adding require 'rbpdf' to config/additional_environment.rb.


Files

No data to display

Actions

Also available in: Atom PDF