JVMのパフォーマンスチューニングメモリオーバーフロー

よく使用されるツールやコマンド

JPS JSTATトップjstack jmapのマット工具

 トップ-HPのpidはプロセス・スレッドの情報を表示することができます

スレッド情報が、-p PIDが指定-Hディスプレイ

JPS:JPS -l PID:仮想マシンは、メインクラス名とプロセスなどのpid仮想マシンが実行されるプロセスやディスプレイを実行している一覧表示することができます

Jstackコマンド

jstackは、Java仮想マシンがスタックトレースツールが付属しています。現時点スレッドのJava仮想マシンのスナップショットを生成するために使用されます。スナップショットは、各実行スレッド・スタック・コレクション、スレッドのスナップショットを生成する主な目的は、スレッドは、スレッド間のデッドロック、無限ループとして長い休止を表示配置することである、現在のスレッドのJava仮想マシン内のメソッドである、長いによって引き起こされる外部リソースを要求し上のように待機する時間。

スレッドの状態:

NEW:起動しません。これは、ダンプには表示されません。

RUNNABLE:仮想マシン内で実行されます。あなたはまだそれがロックを獲得したことを、言葉を見ることができる内部の状態を実行して、それがロックされることがあります。

BLOCKED:モニターロック用ブロックと待機で。ロック(シンクロナイザ)がライブブロックすることです。

WATING:特定のアクションを実行するために別のスレッドを無期限に待機。条件やモニタが発生したために声明の中でなど、通常は()、待機()、スリープ()、参加()公園に滞在、待っています。

TIMED_WATING:期限を定めた別のスレッドの特定の操作を待っています。そして、WAITING差は、制限時間待ち(タイムアウト)と待機()およびその他のステートメントです。

TERMINATED:それは終了しました。

 

例一:

パブリッククラスMyThread実装Runnableを{

    ます。public void実行(){

        同期(本){

            以下のために(INT iが= 0; I <1; i--){

                System.out.println(にThread.currentThread()のgetName()+にThread.currentThread()のgetId()+ "ループを行う" + I。。);

            }

        }

    }

    パブリック静的無効メイン(文字列[] args){

        MyThread T1 =新しいMyThread()。

        TA =新しいスレッドスレッド(T1、 "A");

        スレッドTB =新しいスレッド(T1、 "B")。

        ta.start();

        tb.start();

    }

}

 

jstack -l 6212> D:\ 11.jstack.txt

 

2019年6月25日午後十一時○○分05秒

完全なスレッドダンプは、Java HotSpot(TM)64ビットサーバーVM(25.201-B09混合モード):

 

"DestroyJavaVMは" #13 PRIO = 5 os_prio = 0 TID = 0x0000000002b7e800 NID = 0xb80 [0x0000000000000000]状態で待機

   java.lang.Thread.State:RUNNABLE

 

"B" #12 PRIO = 5 os_prio = 0 TID = 0x000000001b4b1800 NID = 0x1d0モニタエントリを待っ[0x000000001c12f000]

   java.lang.Thread.State:BLOCKED(オブジェクトモニター上)

        MyThread.runで(MyThread.java:12)

        - ロックを待機している<0x0000000702c02720>(MyThread)

        java.lang.Thread.runで(Thread.java:748)

 

"A" #11 PRIO = 5 os_prio = 0 TID = 0x000000001b4b1000 NID = 0x1cecランナブル[0x000000001c02f000]

   java.lang.Thread.State:RUNNABLE

        java.io.FileOutputStream.writeBytesで(ネイティブメソッド)

        java.io.FileOutputStream.writeで(FileOutputStream.java:326)

        java.io.BufferedOutputStream.flushBufferで(BufferedOutputStream.java:82)

        java.io.BufferedOutputStream.flushで(BufferedOutputStream.java:140)

        - ロックされた<0x0000000702c407f8>(java.io.BufferedOutputStream)

        java.io.PrintStream.writeで(PrintStream.java:482)

        - ロックされた<0x0000000702c04820>(に、java.io.PrintStream)

        ...

        MyThread.runで(MyThread.java:13)

        - ロックされた<0x0000000702c02720>(MyThread)

        java.lang.Thread.runで(Thread.java:748)

 

高いCPUリソーススレッドのPIDを占めるように取得されたダンプ時間、仮想マシンはtopコマンドにされ、各スレッドのスレッドダンプでの16進数の値にpidのターンはNIDを持って、対応を見つけますNIDことができます。

ここでは、各項目の具体的な意味がされ、私たちが最も懸念しているところですが、また、地元のスタックトレースを通じて問題を発見します

-thread名: "A"

- スレッドの優先順位:PRIO = 10

-javaスレッド識別子:TID = 0x09b7b400

-nativeスレッド識別子:NID = 0x12f2

- スレッドの状態:はObject.wait()java.lang.Thread.State中:TIMED_WAITING(オブジェクトモニタ上) 

- スレッドスタックの先頭アドレス:[0xb30f9000]

例二:

ます。public void実行(){

        同期(本){

            以下のために(INT iが= 0; I <1; i--){

                。//System.out.println(Thread.currentThread()のgetName()+にThread.currentThread()のgetId()+ "ループを行う" + I)。

                {試します

                    this.wait();

                }キャッチ(InterruptedExceptionある電子){

                    e.printStackTrace();

                }

            }

        }

    }

 

2019年6月25日夜09時52分25秒

完全なスレッドダンプは、Java HotSpot(TM)64ビットサーバーVM(25.201-B09混合モード):

 

"DestroyJavaVMは" #13 PRIO = 5 os_prio = 0 TID = 0x000000000252e800 NID = 0x3e5c [0x0000000000000000]状態で待機

   java.lang.Thread.State:RUNNABLE

 

Object.waitにおける "B" #12 PRIO = 5 os_prio = 0 TID = 0x000000001b19b000 NID = 0x4d38()[0x000000001bdee000]

   java.lang.Thread.State:(オブジェクトモニター上)WAITING

        java.lang.Object.waitで(ネイティブメソッド)

        - <0x000000078105ba78>を待っている(MyThread)

        java.lang.Object.waitで(Object.java:502)

        MyThread.runで(MyThread.java:15)

        - ロックされた<0x000000078105ba78>(MyThread)

        java.lang.Thread.runで(Thread.java:748)

 "A" #11 PRIO = 5 os_prio = 0 TID = 0x000000001b198000 NID = 0x2b18はObject.wait()[0x000000001bcef000]で

   java.lang.Thread.State:(オブジェクトモニター上)WAITING

        java.lang.Object.waitで(ネイティブメソッド)

        - <0x000000078105ba78>で待機している(MyThreaの D)

        java.lang.Object.waitで(Object.java:502)

        MyThread.runで(MyThread.java:15)

        - ロックされた<0x000000078105ba78>(MyThread)

        java.lang.Thread.runで(Thread.java:748)

 使用MATメモリリーク分析ツール

jmapのコマンド

メモリを分析するために、あなたは最初に必要jmapのコマンドを使用する必要がある文書の分析のための生のメモリを取得します。JDKツールを通じて、メモリイメージファイルを生成するためjmapの独自のツールで、開発者は、ファイルを迅速に生成することができますダンプ。開発者は、jmapは、一般的に使用されるコマンドを確認するために、「jmapの-help」コマンドを使用することができます

ダンプファイルを取得する方法は2つあります。

まず、上記のjmapはツール生成によって、あなたはJavaのプロセス・ダンプ・ファイルのいずれかを生成することができます。

第二に、「-XX:+ HeapDumpOnOutOfMemoryError」設定オプションによって生成されたJVMパラメータと - :「XX HeapDumpPath」の意味は、プログラムがOUTOFMEMORYを表示されたときに表現され、適切なディレクトリにダンプファイルを生成し、もします「:HeapDumpPath XX」は、現在のディレクトリにダンプファイルを生成しているオプションを指定しないでください。

そこにダンプファイルを取得するには2つの方法がありますが、アカウントに、本番環境を服用すると、オンラインそれらを分析することはほとんど不可能である、主にオフライン解析が、jmapは+ MATツールの使用が最も一般的な組み合わせです。

ヒープオーバーフローのシミュレーション・シナリオ:セット:-Xms10m -Xmx10m -XX:+ HeapDumpOnOutOfMemoryError -XX:HeapDumpPath = E:\ダンプ

 

@テスト

    ます。public void testOOM(){

        一覧<人>のユーザー=新しいのArrayList <人>();

        一方、(TRUE){

            users.add(新しい人( ""、1));

        }

    }

概要オプション:

MATの打ち上げ成功後、メニューオプションから「ファイル - >開くヒープダンプ...」指定されたダンプ・ファイルの概要オプションが生成されますオープンは、次の通り:

 

 

 円グラフの形で概要オプションは、ケーキの異なる色の各々は、メモリ消費量の異なるパーセンテージを表すプログラムメモリ消費のいくつかの基本的な情報を含みます。

ドミネーターツリーオプション:

コードがメモリリーク箇所を特定する必要がある場合、我々はドミネーターツリーメニューオプションでトラブルシューティングを行うことができます。ドミネーターツリーリストを提供します。ドミネーターツリー:オブジェクト間の支配ツリーの関係。あなたはGCルートからYはXを受けるすべてのパスに到達した場合、我々は、XがYを支配し、またはXはドミネーターYのだと言います。支配ツリーは、図複雑なオブジェクトから、システムによって計算されます。支配ツリーMATから最大物体に見られる次のように、各オブジェクトのメモリと分母を占めます。

 

 

 以下の、さらにアプリケーションは、クラスオブジェクトに対応する属性値も表示することがあり、内層を参照してください。

 

ヒストグラムオプション:

ヒストグラム解析は、各クラスの数のヒストグラムリストの例、アクション下のヒストグラムをクリックすることができ、次のような結果が得られました:

 

あなたがクラス特性を照会する必要がある場合は、私たちは、このような「erson」を見つけると、通常の試合で見つけるために、クラス名やキーワードの最初の行を入力することができます。

 

GCルートへのパス:

    RCのルーツチェーンへのオブジェクト参照を見ます

    メモリリークのトラブルシューティングを行う場合は通常、私たちは見ることを意味し、すべてのファントム/弱い/ソフトetc.referencesを除外することを選択しますファントム参照/弱参照/ソフト参照するので、偽の参照/弱参照/ソフト参照および他の参考チェーン除外するオブジェクトを直接GCにリサイクルすることができ、我々は見てみたいがある場合は、その後、メモリリークがあり、その後、トラブルシューティングの特定の参照に行き、(GCが保証HeapDumpの出発をエクスポートする前に、手動に)参照のオブジェクト強力なチェーンがあるかどうかであります

 

总结:遇到线上问题,首先确认排查问题的思路:

查看日志

    查看CPU情况 top

    查看TCP情况 netstat

    查看java线程,jstack

    查看java堆,jmap

通过MAT分析堆文件,寻找无法被回收的对象

 

问题排查

1.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取比较多条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
2.检查代码中是否有死循环或递归调用。 

3.检查是否有大循环重复产生新对象实体。 

4.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

5.结合内存查看工具动态查看内存使用情况

问题解决

1.检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。对代码进行走查和分析,找出可能发生内存溢出的位置。修正。

2.修改JVM启动参数,直接增加内存。

第一个异常:设置堆的方法是通过-Xms(堆的最小值),-Xmx(堆的最大值)

第一个异常:设置栈大小的方法是设置-Xss参数-Xss100k

第三个异常:设置元空间-XX:PermSize和-XX:MaxPermSize参数(java8中去掉了PermGen(1.8前称永久代,主要用来 存放Class的静态信息,Main方法信息,常量信息,静态方法和变量信息,共享变量等信息 参数设置示例: -XX:PermSize=5M -XX:MaxPermSize=7M) 改为 Metaspace 默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小) 新参数(MaxMetaspaceSize)用于限制本地内存分配给类元数据的大小。如果没有指定这个参数,元空间会在运行时根据需要动态调整)

总结

内存查看工具有许多,比较有名的有:mt、Optimizeit Profiler、JProbe Profiler、JinSight和Java1.5的Jconsole、visualVM(BTrace动态日志,不用修改服务可以加日志)等。它们的基本工作原理大同小异,都是监测Java程序运行时所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化。开发人员可以根据这些信息判断程序是否有内存泄漏问题。一般来说,一个正常的系统在其启动完成后其内存的占用量是基本稳定的,而不应该是无限制的增长的。持续地观察系统运行时使用的内存的大小,可以看到在内存使用监控窗口中是基本规则的锯齿形的图线,如果内存的大小持续地增长,则说明系统存在内存泄漏问题。通过间隔一段时间取一次内存快照,然后对内存快照中对象的使用与引用等信息进行比对与分析,可以找出是哪个类的对象在泄漏。

おすすめ

転載: www.cnblogs.com/leifonlyone/p/12381159.html