1

JRuby on Rails と Torquebox で Prawn を使用して大きなドキュメント (数百ページ以上) をコンパイルすると、重大なメモリ使用量の問題が発生します。

私たちのアプリでは基本的に、ユーザーが一連の PDF ドキュメントをアップロードして、それらを 1 つにまとめることができます。Prawn 部分はファイルのリストを受け取り、ページごとにループし、出力ドキュメントdocument.start_new_page(template: 'filename')に各ページを挿入し、挿入後に各ページにいくつかの小さな追加 (ページ番号とタブの描画) を行います。関連するコードの一部を以下にコピーします。

生成しているファイルの一部はかなり大きいですが、メモリ使用量は依然としてバランスが取れていないようです。たとえば、38MB のファイルを生成すると、4GB 以上の RAM (!) が必要になります。この特定のファイルは、30 個のファイルを照合することによって作成されました。最大の 2 つのサイズは 7MB と 5MB で、ほとんどはわずか数 100KB ですが、サーバーが落ちないように Java のヒープサイズを 5GB に増やす必要がありました。

メモリ使用量が非常に多いことに驚くべきでしょうか? 私たちは何か間違ったことをしていますか?修正はありますか? どうもありがとう。

サーバーのセットアップ:

JRuby バージョン: 1.7.4 Rails バージョン: 4.0.0、本番モードで実行 Torquebox: 3.0.0 OS: 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()です。入力ファイルごとに 1 回呼び出されます。@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
4

0 に答える 0