3

odf ドキュメント操作に Java odftoolkit ライブラリ (simple-odf-0.6.6) を使用しています。ループ内のすべてのドキュメントを繰り返します。

TextDocument textdoc = TextDocument.loadDocument(odtFileName);
.
changing content of document
.
textdoc.save(anotherOdtFileName);
textdoc.close();
//then all resources/streams are correctly closed, checked that many times by my colleagues :)

何千ものドキュメントを繰り返し処理していると、Java アプリがすべてのメモリをゆっくりと消費し、GC がメモリを解放しようとするため、すべてが遅くなります。OutOfMemoryException を取得していません。

JVM メモリ サイズと GC オプションを調整しようとしました ( http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html ) - アプリケーションはあと数分待機しますが、すべてのメモリが再び消費されます.

これは、アプリケーションが使用可能なすべてのメモリに達したときに取得されたダンプのサンプルです。

652.147: [Full GC 652.147: [Tenured: 454655K->454655K(454656K), 2.2387530 secs] 659263K->659216K(659264K), [Perm : 41836K->41836K(42112K)], 2.2388570 secs] [Times: user=2.25 sys=0.00, real=2.23 secs] 
654.387: [Full GC 654.387: [Tenured: 454656K->454656K(454656K), 2.2661510 secs] 659263K->659223K(659264K), [Perm : 41836K->41836K(42112K)], 2.2663190 secs] [Times: user=2.26 sys=0.00, real=2.26 secs] 
656.654: [Full GC 656.654: [Tenured: 454656K->454656K(454656K), 2.4117680 secs] 659263K->659229K(659264K), [Perm : 41836K->41836K(42112K)], 2.4118970 secs] [Times: user=2.41 sys=0.00, real=2.41 secs]

わずか数 kB しか解放されておらず、GC が非常に遅い (2 秒以上) ことがわかります。

このjmap ヒストグラムは、最大の消費者を示しています。

 num     #instances         #bytes  class name
----------------------------------------------
   1:       2535190       99077856  [C
   2:       2529791       60714984  java.lang.String
   3:         21085       27956544  [B
   4:        389820       16181680  [Ljava.lang.Object;
   5:        147111       13373896  [Ljava.util.HashMap$Entry;
   6:        108426       13180496  <constMethodKlass>
   7:        518834       12452016  java.util.HashMap$Entry
   8:        108426        9547136  <methodKlass>
   9:        321713        7721112  java.util.Vector
  10:        306308        7351392  org.apache.xerces.dom.AttributeMap
  11:        144353        6928944  java.util.HashMap
  12:         10230        5879960  <constantPoolKlass>
  13:         10230        5089344  <instanceKlassKlass>
  14:        114065        4562600  org.odftoolkit.odfdom.dom.attribute.text.TextStyleNameAttribute
  15:         58248        4193856  org.odftoolkit.odfdom.incubator.doc.text.OdfTextParagraph
  16:         90041        3601640  org.odftoolkit.odfdom.pkg.OdfAlienAttribute
  17:         36437        3459000  [I
  18:         48609        3110976  java.util.zip.ZipEntry
  19:          7454        2939616  <constantPoolCacheKlass>
  20:         36491        2627352  org.odftoolkit.odfdom.incubator.doc.style.OdfStyle
  21:         36399        2620728  org.odftoolkit.odfdom.incubator.doc.text.OdfTextSpan
  22:         58397        2335880  org.odftoolkit.odfdom.dom.attribute.style.StyleNameAttribute
  23:         65517        2096544  org.apache.xerces.dom.TextImpl
  24:         24270        1747440  org.odftoolkit.odfdom.incubator.doc.text.OdfTextListLevelStyleBullet
  25:         36511        1460440  org.odftoolkit.odfdom.dom.attribute.style.StyleFamilyAttribute
  26:         24335        1362760  org.odftoolkit.odfdom.dom.element.style.StyleParagraphPropertiesElement
  27:         24320        1361920  org.odftoolkit.odfdom.dom.element.style.StyleListLevelPropertiesElement
  28:         24320        1361920  org.odftoolkit.odfdom.dom.element.style.StyleListLevelLabelAlignmentElement
  29:         10933        1316952  java.lang.Class
  30:         29175        1167000  org.odftoolkit.odfdom.dom.attribute.style.StyleParentStyleNameAttribute
  31:         19464        1089984  org.odftoolkit.odfdom.dom.element.style.StyleFontFaceElement
  32:         68003        1088048  java.lang.Integer
  33:          3531        1082640  <methodDataKlass>
  34:         26757        1070280  org.odftoolkit.odfdom.dom.attribute.fo.FoMarginLeftAttribute
  35:         26752        1070080  org.odftoolkit.odfdom.dom.attribute.fo.FoTextIndentAttribute
  36:         24330         973200  org.odftoolkit.odfdom.dom.attribute.style.StyleWritingModeAttribute
  32:         68003        1088048  java.lang.Integer
  33:          3531        1082640  <methodDataKlass>
  34:         26757        1070280  org.odftoolkit.odfdom.dom.attribute.fo.FoMarginLeftAttribute
  35:         26752        1070080  org.odftoolkit.odfdom.dom.attribute.fo.FoTextIndentAttribute
  36:         24330         973200  org.odftoolkit.odfdom.dom.attribute.style.StyleWritingModeAttribute
  37:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextListLevelPositionAndSpaceModeAttribute
  38:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextLevelAttribute
  39:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextListTabStopPositionAttribute
  40:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextLabelFollowedByAttribute
  41:         24315         972600  org.odftoolkit.odfdom.dom.attribute.fo.FoLineHeightAttribute
  42:         24270         970800  org.odftoolkit.odfdom.dom.attribute.text.TextBulletCharAttribute
  43:         17064         955584  org.odftoolkit.odfdom.dom.element.style.StyleTextPropertiesElement
  44:         38372         920928  java.util.ArrayList
  45:         12135         873720  org.odftoolkit.odfdom.dom.element.text.TextAElement

ご覧のとおり、メモリには odftoolkit 関連のクラスがたくさんあります。

この問題に対処する効果的な方法はありますか? 実行時にアプリから odftoolkit をアンロードし、再度ロードしてメモリ内のすべてのオブジェクトを削除できる可能性があると便利です (明らかに、一緒にリンクされているため、GC は何も役に立ちません)。

重要なコードをドキュメントの小さなグループに対して別のプロセスとして実行することも検討していますが、それでは問題の原因が解決されません。

4

3 に答える 3

4

ライブラリ自体に何らかの問題があるか、ライブラリを適切に使用していないために、ストレージ リークが発生している可能性があります。どちらを知るには、適切に構築された最小限の再現可能な例が必要です。

パフォーマンスの低下は、アプリケーションが GC の実行により多くの時間を費やし、メモリの再利用がますます少なくなる、典型的な「GC デス スパイラル」動作です。GC が数分または数時間スラッシングした後、最終的に OOME につながる可能性があります。

UseGCOverheadLimit死のスパイラルに対処する方法は、 JVM スイッチを使用してガベージ コレクションに費やされる時間に上限を設けることです。GC が指定された時間の割合を超えると、JVM は「GC オーバーヘッド制限を超えました」というメッセージとともに OOME をプロアクティブにスローします。これは良いことです...一般的に言えば。

次に、ストレージ リークを突き止めようとします。


Java ストレージ リークの追跡は、多くのリソースでカバーされています。手始めに、このトピックに関する StackOverflow Q&A を次に示します。

基本的な考え方は、リークしているオブジェクトを特定するためのツール (およびツールは多数あります) を使用し、オブジェクト参照のチェーンをさかのぼって、到達できないはずのオブジェクトが到達可能である理由を見つけることです。

于 2013-05-29T07:21:18.527 に答える
2

いくつかのことを確認するためにいくつかのテストを書くことができます:

  1. 最も単純なケースでは、lib自体がリークしていますか? たとえば、次のようなコードを使用します。

    public void loadSaveDocument(String fileInName, String fileOutName) throws Exception {
        OutputStream fileOutStream = new FileOutputStream(fileOutName);
        TextDocument textdoc = TextDocument.loadDocument(fileInName);
        textdoc.addParagraph("added text");
        textdoc.save(fileOutStream);
        textdoc.close();
    }
    
  2. はいの場合、実用的な解決策は、前述のように別のプロセスを使用して回避策を見つけることです。

  3. 「いいえ」の場合、リークの原因となっている特定のドキュメントがありますか? 上記のコードですべてのドキュメントを実行してみてください。
  4. または、リークの原因となっている特定のドキュメントがない場合、使用しているドキュメントの特定の変更がリークの原因である可能性がありますか?
  5. いいえの場合は、単純なコードとアプリケーション コードの違いを確認してください。

また、JProfiler などのプロファイラーを使用して、いくつかのスナップショットを作成することもお勧めします。JProfilerを使用してJavaでメモリリークを見つける方法を参照してください。使い方の答えは。

于 2013-05-29T09:37:39.450 に答える