在使用 Prawn 与 JRuby on Rails 和 Torquebox 编译大型文档(数百页以上)时,我们遇到了严重的内存使用问题。
我们的应用程序基本上允许用户上传一堆 PDF 文档并将它们整理成一个。Prawn 部分获取一个文件列表,逐页遍历每个文件,将每个页面插入到我们的输出文档中,document.start_new_page(template: 'filename')
并在插入后对每个页面进行一些小的添加(绘制页码和标签)。部分相关代码复制如下。
尽管我们生成的一些文件相当大,但内存使用似乎仍然不成比例。例如,生成一个 38MB 的文件会占用超过 4GB 的 RAM (!)。这个特定的文件是通过整理 30 个文件创建的,最大的两个文件大小分别为 7MB 和 5MB,大多数只有几个 100KB - 但我们必须将 Java 的堆大小增加到 5GB 以防止服务器崩溃。
我们是否应该对我们的内存使用量如此之高感到惊讶?我们做错了什么,有解决办法吗?非常感谢。
我们的服务器设置:
JRuby 版本:1.7.4 Rails 版本:4.0.0,在生产模式下运行 Torquebox:3.0.0 操作系统:Ubuntu 12.04 LTS Prawn 版本:1.0.0rc2 JAVA_OPTS:-server -XX:+UseCompressedOops -Xms512m -Xmx5000m -XX:MaxPermSize =512m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true
这是代码中最相关的部分:add_file()
为每个输入文件调用一次。请注意,有一个对 的调用@document.start_new_page()
,它实际上插入了一个新页面,然后是对 的调用start_new_page()
,它不插入一个新页面,但确保page.dictionary.date
正确设置。我不知道这是否与我们的记忆问题有关。
def create_or_update_document(opts)
if @document
@document.start_new_page(opts)
else
opts[:margin] = 0
@document = Prawn::Document.new(opts)
@document.font_size 12
end
end
def add_file(file)
puts " add_file() filename=#{file['full_path']}"
filename = file['full_path']
num_pages = file['pagecount']
(1..num_pages).each do |page_number|
puts " Adding page: #{page_number}"
# take the page defined in file 'filename' and insert it into the
# @document we're building
create_or_update_document(:template => filename, :template_page => page_number)
# this call to start_new_page doesn't change our @document, but
# it ensures that 'page.dictionary.data' contains the settings
# (:Rotate, etc) from the source PDF
start_new_page(:template => filename, :template_page => page_number)
puts " Page size: width=#{page_width} height=#{page_height} Rotate: #{page.dictionary.data[:Rotate]}"
# add destination for internal links e.g. from table of contents or tabs
@document.add_dest("page#{@current_page_number}", @document.dest_fit)
rotation = page.dictionary.data[:Rotate]
case rotation
when 90
translate_x = 0
translate_y = -page_width
page_number_x = page_height - RightMargin
tab_page_height = page_width
when 180
translate_x = -page_width
translate_y = -page_height
page_number_x = page_width - RightMargin
tab_page_height = page_height
when 270
translate_x = -page_height
translate_y = 0
page_number_x = page_height - RightMargin
tab_page_height = page_width
else
translate_x = 0
translate_y = 0
rotation = 0
page_number_x = page_width - RightMargin
tab_page_height = page_height
end
@document.rotate(rotation, :origin => [0,0]) do
@document.translate(translate_x,translate_y) do
if @pack.include_tabs
add_tabs(tab_page_height, page_number_x, @current_page_number)
end
@document.text_box "<font name='Georgia' size='12'>#{@current_page_number}</font>", at: [page_number_x, BottomMargin + 14], inline_format: true, width: RightMargin + 100
end
end
@current_page_number = @current_page_number + 1
end
end