リークスレッドのメモリー・リークの調査
あなたが唯一の特定のプロセスを気にしている場合、直接右のパス処理ロジックへの復帰
の説明リンク:https://www.cnblogs.com/guozp/p/10597327.html
財団
メモリリーク(メモリリーク)
- メモリ内のJava JVMは、経営者の責任において、GCによるガベージコレクションされているので、メモリリークの問題は、通常の状態では発生しません、見過ごされることは容易です。
- メモリリークが役に立たないオブジェクト(もはや使用されるオブジェクト)を連続的または役に立たないオブジェクトがメモリを占有し、メモリは、メモリリークと呼ばれるメモリ空間の浪費をもたらす、時間内に放出されないことを意味します。何のメモリがない場合、より深刻に検出することが時々深刻で、困難なメモリリーク、開発者はメモリリークがあるかわからないので、あなたは自己観察する必要性が、直接OOM割り当てることができます。
- 主な違いとオーバーフローを行います。
メモリー・リーク現象
- ヒープやパーマ/メタスペースの面積がFullGC傾向続け、最後のトリガーを減少、あるいはクラッシュしない、成長しています。
- 低周波アプリケーションならば、それを見つけるのは難しいかもしれないが、最終的に状況は、まだ同じメモリ成長同じと上記の説明であります
パーマ/メタスペースリーク
- ここで、ストレージクラス、メソッド関連オブジェクト、実行時定数オブジェクト。アプリケーションは、クラスの多くをロードされた場合、一般的にパーマ領域に格納された情報が比較的大きくなる。またインターンStringオブジェクトの多数の領域につながる可能性が成長し続けます。
- もっと一般的な動的にコンパイルGroovyのクラスの原因の漏れがあります。ここでは起動しません
ヒープリーク
より一般的なメモリリーク
- 静的なコレクションは、メモリリークが発生します
- リスナー:しかし、多くの場合、ときにオブジェクトを解放するため、メモリリークの可能性を高め、これらのリスナーを削除するには覚えていませんでした。
- 様々な接続、データベース、ネットワーク、IOなど
- そのようなクラスの参照などの内部および外部モジュール:内部クラスへの参照が1を忘れることは比較的容易である、とフォローアップのクラスオブジェクトのシリーズにはつながらないかもしれリリース後にリリースされていません。内部クラスでは放出されないように、物体の周囲がメモリリークが生じる、解放されません、非静的内部クラスは、その周辺のオブジェクトへの強い暗黙参照されるオブジェクト
- シングルトン:Singletonパターンの不正使用がメモリリークに起因する共通の問題である初期化された後のライフサイクルを通じてJVMにシングルトンオブジェクトの外に保持していた場合、シングルトンオブジェクトは、(静的変数)が存在しますオブジェクトへの参照は、そのオブジェクトは、通常の回復JVM、メモリリークの外側ではありません
- 他のサードパーティ製のクラス
本実施形態(スレッドリーク)
この場合、現象
-
80%+メモリ使用率ほど、そして、94%の最高点を上昇し続け
-
yongGCより頻繁に、メモリがFullGCで、比較的高い場合
-
より多くの皆様スレッド、最高点は2ワットに達し+(これはより重要であるが、それはこの時点に注意を払うことで後ろ)
- 例外の数が多い、主に3つのタイプを伴うログ
-
fastJosnエラー
-
言語翻訳サービスコールインタフェース識別エラー
-
ドッキングアルゴリズムは、2乗誤差のパケット要求を提供しました
-
迂回は単に間違って行くために始めました
- ただ、より多くのメモリ、80%以上+、論理的思考や記憶に関連したこの時間を取る機械を発見し始めて
- この時間は、現象1,2,4に応じて、スレッドの数を観察するために行かなかった後,,このプロセスは現象3、無益な調査を見つけることができませんでした、現象の再配置は、3を発見しました
- (消費経由による多くのサービスに、この場合には、MQを開始しました)という考えで、その結果、原因エラーログ現象に4より、プラスの高いメモリ使用量
- 増加MQ 4エラーリトライキュータスク現象の結果は、メッセージのバックログが増加し、メモリに得られ、増加消費MQタスクキューにつながります
- 増加による異常にタスク異常コードロジックタスクキューの長さが増加している、その結果、スレッドプールを再試行するために、メモリの増加につながります
疑問を解決するための迂回
- 異常なポジショニング
- fastJson異常を解決する(fastJsonは、オーバーフローエラーが生じ、解析時にロングタイプの地図に書き込まれ、デフォルトは、INTパーサによって解決される。しかし、このバグでは、以前のバージョンのバグのfastJsonを踏ん感じるだろうエラーを見て、制限がint、int型のデフォルトよりも小さい場合、それ以降のバージョンでは、さえもロングタイプに今修正し、int型の制限、長いデフォルトを超えて、解決される。ロングとしてクラス変数。直接解析、直接ロングタイプ)が、ビジネスクラスコードを直接解析に使用され、我々は2つの方形のパッケージクラスには、int型を使用してint型が、メッセージの値は、いくつかの値を超えました
- eas算法链路调用错误,之前就有(404),但是没有定位到具体原因,有知道的望指点下,这里用try catch做了处理
- 翻译服务异常,这里没定位到具体原因,重启应用后恢复,这里忘记了做try catch,看来依赖外部服务需要全部try下
- 确认是否是业务逻辑中错误重试队列问题
- 否,和业务相关才会走入重试流程,还在后面
- 确认是否是Mq消息队列积压,以及Mq重试队列消息积压导致,确认是否是线程自动调整(metaq/rocketmq)
- 否,Mq做了消费队列安全保护
- consumer异步拉取broker中的消息,processQueue中消息过多就会控制拉取的速率。对于并发的处理场景, 存在三种控制的策略:
1. queue中的个数是否超过1000
2. 估算msg占用的内存大小是否超过100MB
3. queue中仍然存在的msg(多半是消费失败的,且回馈broker失败的)的offset的间隔,过大可能表示会有更多的重复,默认最大间隔是2000。 - 流控源码类:com.alibaba.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl#pullMessage,圈中的变量在默认的类中都有初始值
- metaq也会自己做动态线程调整,理论上当线程不够用时,增加线程,adjustThreadPoolNumsThreshold默认值10w,当线程比较多时,减少线程,但是代码被注释了,理论上应该没有自动调整过程,所以这里也不会因为任务过多增加过多线程
-
在start启动的时候,启动了一批定时任务
-
定时任务中启动了调整线程的定时任务
-
启动调整任务
-
回归正途的处理逻辑
- 经过上述分析,发现并不是因为异常导致的任务队列增加过多导致,这个时候,发现了现象3,活动线程数明显过多,肯定是线程泄露,gc不能回收,导致内存一直在增长,所以到这里,基本上就已经确认是问题由什么导致,接下来要做的就是确认是这个原因导致,以及定位到具体的代码块
- 如果没有具体的监控,一般就是看机器内存状况,cpu,以及jvm的heap,gc,有明显线程状况的,可jstack相关线程等,最终依然无法定位到具体代码块的可以dump后分析
登录涉事机器
-
top,观察内存占用率(这里图是重启之后一段时间的)但是cpu占用率比较高,很快就降下去了,这里耽误了一下时间,top -Hp pid,确认那个线程占用率高,jstack看了下对应的线程在作甚
-
确认线程是否指定大小,未发现指定,使用的默认值大小
- 查看heap,gc状况
- 查看线程状况,可jstack线程,发现线程较多,也能定位到,但是为了方便,遂dump一份数据详细观察堆栈
- 线程个数
-
cat /proc/{pid}/status (线程数竟然这么多)
-
由于线程数比较多,而依然可以创建,查看Linux普通用户所允许创建的进程数,使用命令:cat /etc/security/limits.d/90-nproc.conf ,值比较到,远超当前的个数
-
-
线程信息
-
线程状态
- 定位到问题线程
- AbstractMultiworkerIOReactor ==》 httpAsycClient ==》如图所示不能直接定位到代码块,所以maven定位引用jar的服务 ==> 具体二方包
-
如果每次都new线程而不结束,gc中线程是root节点,如果线程没有结束,不会被回收,所以如果创建大量运行的线程,会导致内存占用量上升,但是线上到底能创建多少线程呢?
- 问题代码块
-
方法开始(每次都初始化一个新的客户端,底层封装使用httpAsyncClient,httpAsyncClient使用NIO模型,初始化包含一个boss,10个work线程)
-
この方法は終了する(メソッドの端部がshutdow呼ばれます)
-
-
現象と対応するスレッドのスタック情報によると、あなたはスレッドがここに溢れているかを決定することができ、シャットダウン方法クライアントスレッドプールは、最初のスレッドがNIOモード、終わりではないので、スレッドは受注残が増加してきた、あなたはシングルを変更することができるので、その結果、閉じ失敗ですモードの実施形態では、ライン上の問題を解決するために、スレッドプールを使用して、制限システム
- 线程个数
ソースコード解析のhttpAsyncClient一部
- スタート
- 常設のスレッド
- 原子炉スレッド负责接続
- ワーカースレッド负责の読み取りと書き込み
- スレッドプールの名前、プール-の上に表示される-thread-スレッド
- ioEventDispatchスレッド
- スタート
- ワーカースレッド
- ワーカースレッド名
- IOの労働者は、詳細な実行します
- ワーカースレッドの実装
- スタート
- 常設のスレッド
- シャットダウンは、コールの後、スレッドはループの外になりませんここで分析、スレッドの終了、および非常に多くの近いリンクのクリーンアップアクション
疑い
- この方法は、新しいクライアントが新しいたびに呼び出されたが、最終的に最終的にシャットダウンと呼ばれてきたが、近くには失敗した理由は、単に、なぜすべての新しいクライアント、その後、シャットダウンの失敗理由をカバーするために、上記のシングルトンを使用します
- 障害が発生した場合のhttpAsyncClientクライアント要求、httpclient.close()ここでは、メインスレッドがスレッド後の内部ソースcloseメソッドを閉じる接続プールによって発見ブロックするようになります、スレッドがありhttpAsyncClientが実行されているが、epollWaitでブロックされている対応、コールがシャットダウン後に閉鎖することができなかった理由を判断するために現在、スレッドが存在しない、スレッドの状態の上に見て、例外ログはありませんが、これは漏れスレッドの主な原因であります
- 通常は非常に奇妙な、ローカルテストのシャットダウン方法を閉じました。あなたが特定の理由を知っている必要があります場合は、展覧会を願っています
- 説明リンク