- ベストアンサー
cloneNodeするとサイズが増える
- XMLのテンプレートを編集して出力するプログラムで、cloneNodeの使用によりメモリリークが発生している。
- Java 1.6での実装で、EntityのフィールドのElementオブジェクトの容量がcloneNodeの実行ごとに増加している。
- データベースはOracle Databaseを使用しており、EntityのフィールドのElementオブジェクトの容量の増加が問題となっている。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
問題にされている点が何かがよくわかりました。少々失礼な確認をしてしまいましたがご容赦ください。 確認された結果からcloneNodeでコピー元のオブジェクト構造のどこかが変化しメモリーの増加が生じるのは確かのように思えます。 >総使用メモリは増加するが、オブジェクトそのもののサイズは変わらないというつもりだったのですが... 自分はこのデータ構造についての詳細を知らないので階層構造のコピーで何が起こる可能性があるかが推測できません。 cloneNodeのAPI Documentをみても「関連するデータとともに UserDataHandlers が指定された場合は、このメソッドから戻る前に、それらのハンドラが該当するパラメータで呼び出されます。」というあたりからハンドラー処理によっては何か起こる可能性があるかな?ぐらいしか思いつきませんでした。この原因をご存じの方がコメントをくだされば一番早いのですが・・・ もし自分が調べるとすれば、メモリーサイズを調べるユーティリティの実装を少し変え、クラスごとのトータルサイズを調べるようにすると思います。cloneNode前後でどのクラスのインスタンスが増加しているのかの情報を手掛かりに原因を推測してゆくといった作戦ですが、これは少々迂遠な方法に思えます。このデータ構造についての知識があればもう少し的確かつ速やかに原因を推測できる気がしますので。 お役に立てず申し訳ありません。
その他の回答 (2)
- KSOH
- ベストアンサー率93% (29/31)
Javaにおいてメモリーリークの定義はGCしても回収されないオブジェクトが不当に残ることだと思います。「不当に残る」というのは「設計上意図した以上の期間にわたり不必要に長い期間GCで回収されずに残る」ということになります。 outputXML()ではentity.getXML()、entity.setXML()を用いているためにElementオブジェクトの量はcloneNode()により一時的に2倍程度になります。しかしoutputXML()の実行中はこれらのElementオブジェクトは出力処理で使用中なのでGCを行っても回収できません。これらはoutputXML()が完了した後でどこからも参照されなくなった時点で初めてGCにより回収可能となります。このように動作しているのであれば前述のようにElementは設計上意図したとおりの期間だけ生存しておりメモリーリークではないと言えます。 そうでなくoutputXML()実行完了後にGCを行っても回収されずに残る(outputXML()を何度も実行する過程でGCした結果の使用中オブジェクトのサイズが増加し続ける)ことを確認済みであればそれは確かにメモリーリークです。その場合はEntityやElementの参照が自らのコード中で参照を残すような論理がないかとか、ライブラリーの中で参照をなんらかの形でキャッシュしていないかを疑うことになります。 内容を拝見していてメモリーリークをどういう意味で使われているのか、具体的にどのようにして何を確認されたのかがはっきりわかりませんでしたので問題をはっきりさせるためにそれを伺いたいと感じました。
補足
起きた事象を時系列順に並べますと 1.上記のプログラムを使用したバッチを実行したところ、途中でOutOfMemoryErrorが発生 2.cloneNodeが怪しそうだったので、Classmexer(http://jyohotushinkogaku.blogspot.jp/2012/11/java.html)を利用し、Entityクラスを下記のように変更して使用メモリを測定 getXML(){ system.out.println(MemoryUtil.deepMemoryUsageOf(XML); //(1) Element returnElement = XML.cloneNode(true); system.out.println(MemoryUtil.deepMemoryUsageOf(XML); //(2) return returnElement; } 3.2の状態でプログラムを実行した結果、(1)では300kbだった使用メモリが(2)では330kbになっており、 以降getXMLが呼ばれるたびに330kb、360kb、390kb……という調子でElementオブジェクトの使用メモリが増加していた。 という顛末です。 使用メモリの増加量は、多少の誤差はあるもののほぼ同じ量でした。 私の考えでは、cloneNodeすることによって総使用メモリは増加するが、オブジェクトそのもののサイズは変わらないというつもりだったのですが。。。
- teketon
- ベストアンサー率65% (141/215)
clone系のメソッドは、一般的にオブジェクトのすべての要素をコピー(Deep Copy)を行う、 非常に高コストのメソッドです。 プログラムを見た限り、EntityのgetXML、setXMLの操作は 所有するXMLオブジェクトの2倍のメモリを必要としています。 あと、キャッシュすることと、clonNodeすることは全く違う理由に思いますが。
お礼
ご回答ありがとうございました。 解消方法はわからなかったため、別の方法を探してみようと思います。