EclipseMATを䜿甚したメモリリヌクの怜出

おそらく、商甚プロゞェクトに関䞎するすべおのJava開発者は、遅かれ早かれメモリリヌクの問題に盎面したす。これは、アプリケヌションパフォヌマンスの䜎䞋を䌎い、ほずんど必然的に、よく知られおいるOutOfMemoryErrorに぀ながりたす。この蚘事では、そのような状況の実際の䟋ず、Eclipce MemoryAnalyzerを䜿甚しおその原因を芋぀ける方法に぀いお怜蚎したす。



前曞き



メモリリヌクは通垞、アプリケヌションの長期操䜜䞭にヒヌプ内の占有メモリ量が増加し、ガベヌゞコレクタが終了した埌も枛少しない状況ず呌ばれたす。ご存知のように、jvmメモリはヒヌプずスタックに分かれおいたす。スタックは単玔なタむプの倉数の倀ずストリヌムのコンテキスト内のオブゞェクトぞの参照を栌玍し、ヒヌプはオブゞェクト自䜓を栌玍したす。たた、ヒヌプにはMetaspaceず呌ばれるスペヌスがあり、ロヌドされたクラスに関するデヌタず、クラス自䜓にバむンドされたデヌタを栌玍したす。むンスタンス、特に静的倉数の倀は栌玍したせん。 Javaマシンによっお定期的に起動されるGarbageCollector以䞋、GCは、参照されなくなったオブゞェクトをヒヌプ内で怜出し、これらのオブゞェクトが占有しおいたメモリを解攟したす。 GC䜜業アルゎリズムは異なり、特に耇雑です。次回GCが起動するずきに、未䜿甚のオブゞェクトを芋぀けるために毎回ヒヌプ党䜓を「怜査」するわけではないため、1回のGCの起動埌に未䜿甚のオブゞェクトがメモリから削陀されるずいう事実に䟝存する䟡倀はありたせんが、アプリケヌションで䜿甚されるメモリの量が安定しおいる堎合長い間明癜な理由もなく成長したので、そのような状況に぀ながった可胜性があるものに぀いお考える時が来たした。



jvmには、倚機胜ナヌティリティVisual VM以䞋、VMず呌びたすが含たれおいたす。 VMを䜿甚するず、グラフ内のjvmの䞻芁なむンゞケヌタヌのダむナミクス、特に、ヒヌプ内の空きメモリず占有メモリの量、ロヌドされたクラス、スレッドの数などを芖芚的に芳察できたす。さらに、VMを䜿甚しお、メモリダンプを取埗しお調べるこずができたす。もちろん、VMではスレッドダンプずアプリケヌションプロファむリングも可胜ですが、これらの機胜の抂芁はこの蚘事の範囲を超えおいたす。この䟋でVMに必芁なのは、仮想マシンに接続しお、最初にメモリ䜿甚量の党䜓像を確認するこずだけです。 VMをリモヌトサヌバヌに接続するには、接続がjmxを介しおいるため、jmxremoteパラメヌタヌをVMで構成する必芁があるこずに泚意しおください。これらのパラメヌタヌの説明に぀いおは、Oracleの公匏ドキュメントたたはHabréに関する倚数の蚘事を参照しおください。



それで、VMを䜿甚しおアプリケヌションサヌバヌに正垞に接続したず仮定し、グラフを芋おみたしょう。







[ヒヌプ]タブで、jvmの合蚈メモリず䜿甚枈みメモリを確認できたす。このタブでは、メタスペヌスタむプのメモリも考慮されおいるこずに泚意しおくださいこれもヒヌプであるため、他の方法です。 [メタスペヌス]タブには、メタデヌタが占有しおいるメモリクラス自䜓ずそれにバむンドされおいるオブゞェクトに関する情報のみが衚瀺されたす。



グラフを芋るず、ヒヌプメモリの合蚈が玄10GB、珟圚の占有スペヌスが玄5.8GBであるこずがわかりたす。グラフの隆起はGC呌び出しに察応し、1018頃から始たるほが盎線隆起なしは、アクティブな割り圓おず割り圓お解陀がなかったため、それ以降、アプリケヌションサヌバヌがほずんど実行されおいないこずを瀺したす必ずしもそうずは限りたせん。メモリ。䞀般に、このグラフは、アプリケヌションサヌバヌの通垞の操䜜に察応したすもちろん、メモリからのみ䜜業を刀断する堎合。問題のグラフは、隆起のない真っ盎ぐな氎平の青い線が、ヒヌプ内のメモリの最倧量を衚すオレンゞ色の線のあたりにあるグラフです。



次に、別のグラフを芋おみたしょう。







ここでは、この蚘事のメむントピックである䟋の分析に盎接行きたす。クラスグラフは、メタスペヌスにロヌドされたクラスの数を瀺し、玄73,000オブゞェクトです。クラスむンスタンスに぀いおではなく、クラス自䜓、぀たりクラス<>タむプのオブゞェクトに぀いお話しおいるずいう事実に泚意を向けたいず思いたす。グラフから、個々のタむプClassAたたはClassBのむンスタンスがいく぀メモリにロヌドされおいるかは明らかではありたせん。おそらく、䜕らかの理由でクラスAタむプの同䞀クラスの数が増加したすか以䞋で説明する䟋では、73,000の䞀意のクラスは絶察に正垞な状況であったず蚀わなければなりたせん。



事実、この蚘事の著者が参加したプロゞェクトの1぀では、蟞曞システムず呌ばれるドメむン゚ンティティ1Cなどのナニバヌサル蚘述、および特定の顧客たたは特定の事業領域に合わせおシステムをカスタマむズするアナリストのためのメカニズムが開発されたした。特別な゚ディタヌを介しお、テヌブルのレベルではなく、「ドキュメント」、「アカりント」、「埓業員」などの抂念で動䜜する、新しい゚ンティティず倉曎する既存の゚ンティティを䜜成するこずによっおビゞネスモデルをモデル化する機䌚がありたした。システムカヌネルは、゚ンティティデヌタ甚のリレヌショナルDBMSにテヌブルを䜜成したした。ナニバヌサルシステムでは、属性倀を履歎に保存でき、デヌタベヌスに远加のサヌビステヌブルを䜜成する必芁があるため、゚ンティティごずにいく぀かのテヌブルを䜜成できたした。



ORMフレヌムワヌクを䜿甚しなければならなかった人々は、テヌブルに぀いお話すこずによっお蚘事のメむントピックから気を取られお、著者が䜕に぀いおであるかをすでに掚枬しおいるず思いたす。プロゞェクトはHibernateを䜿甚し、テヌブルごずにEntityBeanクラスが必芁でした。同時に、アナリストによるシステムの䜜業䞭に新しいテヌブルが動的に䜜成されたため、Hibernate Beanクラスが生成され、開発者が手動で䜜成するこずはありたせんでした。そしお、次䞖代ごずに、玄5䞇から6䞇の新しいクラスが䜜成されたした。システム内のテヌブルは倧幅に少なくなりたしたが玄5〜6千、テヌブルごずに、゚ンティティBeanクラスだけでなく、倚くの補助クラスも生成され、最終的に共通の数倀になりたした。



䜜業の仕組みは以䞋のずおりです。システムの開始時に、゚ンティティBeanクラスず補助クラス以䞋、単にBeanクラスがデヌタベヌス内のメタデヌタに基づいお生成されたした。システムの実行䞭に、Hibernateセッションファクトリがセッションを䜜成し、セッションがBeanクラスオブゞェクトのむンスタンスを䜜成したした。構造を倉曎テヌブルの远加、倉曎するず、Beanクラスが再生成され、新しいセッションファクトリが䜜成されたした。再生埌、新しいファクトリは新しいBeanクラスを䜿甚する新しいセッションを䜜成し、叀いファクトリずセッションは閉じられ、叀いBeanクラスはHibernateむンフラストラクチャオブゞェクトから参照されなくなったため、GCによっおアンロヌドされたした。











ある時点で、ビンクラスの数が次の再生ごずに増加し始めるずいう問題が発生したした。明らかに、これは、䜿甚されるべきではなくなった叀いクラスのセットが、䜕らかの理由でメモリからアンロヌドされなかったずいう事実によるものでした。システムのこの動䜜の理由を理解するために、Eclipse Memory AnalizerMATが圹に立ちたした。



メモリリヌクを芋぀ける



MATはメモリダンプを凊理しお、朜圚的な問題を芋぀けるこずができたすが、最初にこのメモリダンプを取埗する必芁がありたすが、実際の環境では、ダンプの取埗には䞀定の埮劙な違いがありたす。



メモリダンプの削陀



前述のように、メモリダンプは、[







バット]ボタンを抌すこずでVMから盎接削陀できたす。ダンプのサむズが倧きいため、VMはこのタスクに察応できず、[ヒヌプダンプ]ボタンを抌しおからしばらくするずフリヌズする堎合がありたす。さらに、jmxを介しおVMに必芁な補品アプリケヌションサヌバヌに接続できるずいうこずはたったく事実ではありたせん。この堎合、jMapず呌ばれる別のjvmナヌティリティが圹に立ちたす。コマンドラむンで、jvmが実行されおいるサヌバヌ䞊で盎接実行され、远加のダンプパラメヌタを蚭定できたす



。jmap- dump live、format = b、file = / tmp / heapdump.bin 14616 –dumplive



パラメヌタは非垞に重芁です。参照されなくなったオブゞェクトを陀いお、サむズを倧幅に瞮小できたす。



もう1぀の䞀般的な状況は、jvm自䜓がOutOfMemoryErrorでクラッシュするため、手動ダンプが䞍可胜な堎合です。この状況では、-XX+ HeapDumpOnOutOfMemoryErrorオプションが助けになり、それに加えお、-XXHeapDumpPathがあり、キャプチャされたダンプぞのパスを指定できたす。



次に、Eclipse MemoryAnalyzerを䜿甚しおキャプチャされたダンプを開きたす。ファむルのサむズは倧きくなる可胜性があるため数ギガバむト、MemoryAnalyzer.iniファむルに十分なメモリを提䟛する必芁がありたす



-Xmx4096m



MATを䜿甚しお問題を特定する



それで、ロヌドされたクラスの数が初期レベルず比范しお倍数増加し、ガベヌゞコレクションを匷制的に呌び出した埌でも枛少しない状況を考えおみたしょうこれはVMの察応するボタンを抌すこずで実行できたす。



䞊蚘では、Beanクラスを再生成するプロセスずその䜿甚に぀いお抂念的に説明したした。より技術的なレベルでは、次のようになりたした。

 

  • すべおのHibernateセッションが閉じられたすSessionImplクラス
  • 叀いセッションファクトリSessionFactoryImplが閉じられ、LocalSessionFactoryBeanからの叀いセッションファクトリぞの参照がリセットされたす
  • ClassLoaderが再䜜成されたす
  • ゞェネレヌタヌクラスの叀いBeanクラスぞの参照は無効になりたす
  • Beanクラスが再生成されたす


叀いBeanクラスぞの参照がない堎合、ガベヌゞコレクション埌にクラスの数を増やすこずはできたせん。



MATを実行し、以前に取埗したメモリダンプファむルを開きたす。ダンプを開いた埌、MATはメモリ内のオブゞェクトの最倧のチェヌンを衚瀺したす。







Leak Suspectsをクリックするず、詳现



 ãŒè¡šç€ºã•ã‚ŒãŸã™ã€‚それぞれ265 Mの円の2぀のセグメントは、SessionFactoryImplの2぀のむンスタンスです。それらのむンスタンスが2぀ある理由は明らかではなく、ほずんどの堎合、各むンスタンスぱンティティBeanクラスの完党なセットぞの参照を保持しおいたす。 MATは、朜圚的な問題に぀いお次のように通知したす。





 

問題容疑者3は実際には問題ではないこずにすぐに気づきたした。プロゞェクトは独自の蚀語のパヌサヌを実装したした。これはSQL䞊のマルチプラットフォヌムアドオンであり、テヌブルではなくシステム゚ンティティを操䜜でき、121Mはク゚リキャッシュを占有したす。



SessionFactoryImplの2぀のむンスタンスに戻りたしょう。 [クラスの耇補]をクリックしお、各゚ンティティBeanクラスのむンスタンスが実際に2぀あるこずを確認したす。぀たり、゚ンティティBeanの叀いクラスぞのリンクは残り、ほずんどの堎合、これらはSesssionFactoryImplからのリンクです。このクラスの゜ヌスコヌドに基づいお、Beanクラスぞの参照をclassMetaDataフィヌルドに栌玍する必芁がありたす。



Problem Suspect 1をクリックし、次にSessionFactoryImplクラスをクリックしお、コンテキストメニュヌから[List Objects]-> [With outgouingreferences]を遞択したす。このようにしお、SessionFactoryImplによっお参照されるすべおのオブゞェクトを確認できたす。







classMetaDataオブゞェクトを展開し、゚ンティティBeanクラスの配列が実際に栌玍されおいるこずを確認したす。







ここで、ガベヌゞコレクタがSessionFactoryImplの単䞀むンスタンスを砎棄できない原因を理解する必芁がありたす。 Leak Suspects-> Leaks-> Problem Suspect 1に戻るず、SessionFactoryImplぞのリンクに぀ながるリンクのスタックが衚瀺されたす。



 



HTTPセッションのコンテキストを含むSessionInfoImplBeanのentityManager倉数には、Hibernate SessionImplオブゞェクトをキヌずしお䜿甚する配列dbTransactionListenersが含たれおおり、セッションはSessionFactoryImplを参照しおいるこずがわかりたす。



実際には、セッションオブゞェクトは特定の目的でdbTransactionListenersにキャッシュされおおり、Beanクラスが再生成される前は、それらぞの参照がこの配列に残っおいる可胜性がありたす。次に、セッションは、すべおのBeanクラスぞの参照の配列を栌玍するセッションファクトリを参照したした。さらに、セッションぱンティティクラスのむンスタンスぞの参照を保持し、Beanクラス自䜓を参照しおいたした。



したがっお、問題ぞの゚ントリポむントが芋぀かりたした。dbTransactionListenersからの叀いセッションぞの参照であるこずが刀明したした。゚ラヌが修正され、dbTransactionListeners配列がクリアされ始めた埌、問題が修正されたした。



Eclipseメモリアナラむザの機胜



 

したがっお、Eclipse MemoryAnalyzerでは次のこずができたす。



  • オブゞェクトのどのチェヌンが最倧量のメモリを占有しおいるかを調べ、これらのチェヌンぞの゚ントリポむントを決定したすリヌクの疑いがある
  • すべおの着信オブゞェクト参照のツリヌを衚瀺したす环積ポむントぞの最短パス
  • オブゞェクトのすべおの送信参照のツリヌを衚瀺したす[オブゞェクト]-> [オブゞェクトのリスト]-> [送信参照あり]
  • 異なるClassLoaderによっおロヌドされた重耇クラスを参照しおください重耇クラス



All Articles