OutOfMemoryに泣く

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【4/18開催】VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

こんにちは、サイオステクノロジー技術部 武井です。今回は、Javaアプリケーションのプロファイリングについてお話したいと思います。

プロファイリングとは?

Javaでアプリケーションを開発するときのあるあるとして、長時間動かしたら、もしくは一度に大量の負荷をかけたら、OutOfMemoryなんてことよくないでしょうか?私は今まで何度もOOMに枕を涙で濡らしました。

JavaはGC(Garbage Collection)という機能によって、使われなくなった不要なインスタンスを、独自のロジックでメモリからお掃除してくれます。自分でクローズする必要はありません。

しかしながら、自分の預かり知らぬところで、GCが行われるがゆえに、いざ、メモリーリークのあるようなプログラムを作ってしまったときに、その特定が困難を極めることがあります。

たいていはファイルアップロードしたりするときにバカでかいオブジェクトを突っ込んだとか、Staticな変数になにかをたくさん入れてしまったとか、ヒープの容量が足りなかったとかなのですが、そのどれにも該当せず、原因が把握できないときがあります。例えば、外部のライブラリが知らぬ間に悪さをしていたりとか、設定間違えてDBのコネクションプールをものすごい数してしまったりとか(T_T)

そんなときに役に立つのは、プロファイリングツールです。プロファイリングツールとは、その時のヒープの状態を取得し、どのインスタンスがどの程度作成されていて、全体のヒープのどれくらいを占有しているかを把握できるツールです。

早速使ってみましょう

まずは使ってみることが何よりです。今回はEclipse Memory Analyzerを使ってみました。以下のリンクからダウンロードが可能です。

https://www.eclipse.org/mat/downloads.php

あからさまにメモリリークを起こす以下のプログラムを作って動かしてみます。StaticなListに大量にhogeしています。せいぜい100,000インスタンスくらいですので、ドボンはしないと思いますが、怪しい結果にはなりそうですね。Thread.sleepしているのは、プロセスIDを取る時間を稼ぐためです。

public class MemoryLeak {

    private static List<String> list = new ArrayList<String>();

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 100000; i++) {
            list.add("hoge");
        }       
        System.out.println("done");
        Thread.sleep(60000);
    }   
}

 

上記のプログラムが動いているときにプロセスIDを取得します。

# ps ax | grep java

2で取得したプロセスIDをもとに、ヒープのダンプを取得します。

$ jmap -dump:format=b,file=heapdump.hprof [プロセスID]

Eclipse Memory Analyzerを起動して、「File」→「Open Heap Dump」の順にクリックして、先程取得したダンプファイルを選択します。

Screen Shot 2019-05-21 at 22.45.41

 

「Leak Suspects Report」をチェックして「Finish」をクリックします。

Screen Shot 2019-05-21 at 22.46.04

 

以下のような円グラフが表示されます。(a)と(b)がProblem Suspectと表示されています。これが怪しいということになります。ヒープのトータルである921.9KBの半分近くを占めているわけですから。

Screen Shot 2019-05-21 at 22.55.24

 

ちょっと下にスクロールして、犯人であろう2つのオブジェクトのうちの1つの詳細を見てみることにします。ほら、なんかcom.sios.MemoryLeakとか書いているあたりで、なんか怪しそうな雰囲気醸し出していませんでしょうか?期待に胸を膨らませて、下図の「Details >>」をクリックします。

Screen Shot 2019-05-21 at 22.55.34

 

以下のような画面が表示されます。「Shallow Heap」はそのインスタンス単独のメモリのサイズ、「Retained Heap」はそのインスタンス及びそのインスタンスが持つ他のインスタンスも含めたメモリのサイズです。とりあえずでかいのが怪しいです。(¬_¬。) あやしい (;¬¬)アヤシイ・・・

Screen Shot 2019-05-21 at 22.55.42

 

listを右クリックして「List objects」→「with outgoing references」の順にクリックします。

Screen Shot 2019-05-21 at 22.56.01

 

キタ━━━━(゚∀゚)━━━━!!これを見る限り、com.sios.MemoryLeakっていうクラスにあるArrayList型のlist って言う変数が怪しそうです。listってさっきのプログラムでわざとStaticなListにhogeを大量に突っ込んだアレです。valueにもhogeって書いてありますね(ちっちゃくて見にくいですけど)。

Screen Shot 2019-05-21 at 22.57.52

 

想定の結果と、実際の結果が一致したわけです。犯人はやっぱりStaticなlistにhogeを大量に突っ込んだからですね。

まとめ

今回のは非常に簡単な例でした。でも実際は、自分でメモリーリークを起こすようなプログラムを書いていないつもりでも、外部のライブラリが怪しかったりとかして、その原因の特定に困難を極めることがあります。そんなときのプロファイリングツールです。もうくせになりそうです。三度の飯よりプロファイル、どんと来いOutOfMemory。では、快適なプロファイルライフを!!No Profiling,No Life!!ずんちゃずんちゃ。

figure_dance

アバター画像
About 武井 宜行 267 Articles
Microsoft MVP for Azure🌟「最新の技術を楽しくわかりやすく」をモットーにブログtech-lab.sios.jp)で情報を発信🎤得意分野はAzureによるクラウドネイティブな開発(Javaなど)💻「世界一わかりみの深いクラウドネイティブ on Azure」の動画を配信中📹 https://t.co/OMaJYb3pRN
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

2人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる