トラブルシューティングおよび解決、オンラインJVMの悲劇のかつて隠された深い分析を覚えておいてください。

1、背景紙

JVMを最適化し、初心者エンジニアが生噛じりを知っている可能性があり、そして趙は非常に特別なJVMパラメータエラービットがセットされて来たかわからないので、この記事では、JVMの最適化の特別な場合に、この最適化のケース自体があなたを与えるだろうフルGCオンラインシステムは、頻繁に問題につながっています。

それは奇妙なシーンのすべての種類は、誰も出て徐々に蓄積された豊富な実務経験が最適化されたJVMをさせることですので、しかし、我々は、実際に奇妙なシーンの様々なフォローアップの最適化例がたくさんあるき

より多くのシーンを学び、JVMのパフォーマンスの問題に対処する彼らの未来はより便利です。

2、問題を引き起こします

このシーンは大きく以下の手順を発生しました:そう日にするときに設定するフリーハンドを与え、オンラインのシステム、ある日初心者のエンジニアチームは、おそらく気まぐれで、私は、武道の傑作攻略を学んだ、私はオンラインJVMパラメータを見たと思いましたJVM引数

この引数には、それは何ですか?

心配しないで、今ちょうど彼が奇妙な引数を設定することを知って参照するには、以下のケーススタディに続く、その後、事故が起こりました。

大企業は、研究の監視システムの一部から、非常に優れたアクセス類似したZabbixの、OpenFalconや会社で一般的であるため、監視システムは、一般的に行う、あなたは、あなたがそれぞれの上に見ることができ、システムへの直接アクセスを行うことができますいくつかは、マシンのCPU、ディスク、メモリ、ネットワークをロードします。

周波数線グラフ、あなたはあなたのJVMのメモリ使用量の変動の折れ線グラフを見ることができ、そして、あなたのJVMのGCが発生しました。あなたがビジネスレポート指標が含まれている場合、あなたはまた、モニタリングシステムで見ることができます。

システムは、JVMが3回以上のフルGCを発生した場合、通常は機械やシステムのオンライン操作のためのいくつかのアラームを設定し、例えば、あなたがあなたに送信されるアラートを送信する必要があり、10分以内に設定することができます釘のようなSMS、電子メールまたはIMのツール。

このような監視システムは、当社のコラムのカテゴリではありません、私はあなた自身が、情報へのアクセスに我々が説明事実ベースのコマンドラインツールを行くことができることを示唆している、例えばJSTATのために、あなたは、Linux上でいくつかのコマンドを渡すことができ、聞かせてJSTAT自動的にJVMモニター監視結果は、マシン、外出先のファイルに出力することができます。

そして、あなたがファイルにアクセスするために行くことができ、次の日には、あなたもそのマシンいくつかの統計的なGCのJVMを見ることができます。

だから、何の可視化ツールが存在しない、最もシンプルなコマンドラインツールで、実際には、また、同様の効果を再生することができます。

だから、エンジニアはJVMパラメータを設定するには翌日には、フルGC JVMのラインの直接の結果は、頻繁に警報を受け、誰もが非常に奇妙であるので、彼はシステムの調査を開始しました。

3、GCログの表示

我々は彼がGCログを出力するので、一度見つかったアラームは、機械のラインに直接ログイン時にシステムを起動しなければならなかった方法を説明しなければならない、とあなたは、対応するGCログを参照してくださいする前に。

この時点では、ログに記録されている全GC GCの多数を参照してください。

フルGCなぜそれが原因でしょうか?

ログでは、私は言葉「メタデータGCしきい値」は、次のようなログを見ました:

【全GC(メタGCしきい値)xxxxxは、xxxxxは】

このことから、私たちは私たちに似て、実際にJDK 1.8メタデータメタデータエリアリードした後、この頻繁に全GCは、恒久的な世代の前に言ったことを知っています。

この領域は、一般的に、メタデータは、クラスのいくつかを置くつもりJVMにロードされます。

メタデータは、なぜ領域が頻繁に満たされているので、だから、この場合には、非常に奇妙で、[フルGCをトリガ?フルGCしかし、我々はすべてのことが、古いCMSの回復につながるメタデータ領域自体を回復します知っています。

のは、次の図を見てみましょう:


一度隠された深い悲劇JVMライン分析、調査を覚えて、解決



4、ビューメモリ使用メタスペース

そして、もちろん、我々はメモリ使用量メタスペースの面積を見たい、とあなたは、単に監視システムが、彼はあなたを占有変動メタスペースメモリ領域外のグラフが表示されます場合は、JSTATにより観察するポイントすることができ、これは次のようになります。 。


一度隠された深い悲劇JVMライン分析、調査を覚えて、解決



メモリメタスペースの面積は、変動の状態を示して見える、彼は常に増加し、ピークに達した後、彼らは埋めるためにメタスペースの面積を最初に置くされ、その後、自然にそれは完全なGCをトリガーする、完全なGCは、メタスペースの面積がかかりますガベージコレクションは、次のメモリフットプリントので、メタスペースの面積が非常に小さくなっています。

5、アイデアの包括的な分析

私たちは多少の使用感を持たなければならないと信じて、ここを参照してください、常に新しいクラスの農産物は、その後、メタスペース領域がいっぱいになっ停止行くためにメタスペース領域にロードさがあるこのシステムは、その後、トリガーが作動中であることは明らかですクラスのメタスペース・リカバリ領域の全GC離れた部分。

然后这个过程反复的不断的循环,进而造成Metaspace区域反复被占满,然后反复导致Full GC的发生,如下图所示。


一度隠された深い悲劇JVMライン分析、調査を覚えて、解決



6、到底是什么类不停的被加载?

接着我们就有点奇怪了,到底是什么类不停的被加载到JVM的Metaspace区域里去?

这个时候就需要在JVM启动参数中加入如下两个参数了:

“-XX:TraceClassLoading -XX:TraceClassUnloading”

这两个参数,顾名思义,就是追踪类加载和类卸载的情况,他会通过日志打印出来JVM中加载了哪些类,卸载了哪些类。

加入这两个参数之后,我们就可以看到在Tomcat的catalina.out日志文件中,输出了一堆日志,里面显示类似如下的内容:

【Loaded sun.reflect.GeneratedSerializationConstructorAccessor from __JVM_Defined_Class】

明显可以看到,JVM在运行期间不停的加载了大量的所谓“GeneratedSerializationConstructorAccessor”类到了Metaspace区域里去

如下图所示


一度隠された深い悲劇JVMライン分析、調査を覚えて、解決



相信就是因为JVM运行期间不停的加载这种奇怪的类,然后不停的把Metaspace区域占满,才会引发不停的执行Full GC的。

这是一个非常实用的技巧,各位同学一定要掌握,频繁Full GC不光是老年代触发的,有时候也会因为Metaspace区域的类太多而触发。

到此为止,已经慢慢接近真相了。

7、为什么会频繁加载奇怪的类?

接着遇到类似这种问题,我们就应该找一下Google或者是百度了,当然推荐是用Google。你完全可以看看那种不停加载的类,到底是什么类,是你自己写的类?还是说JDK内置的类?

比如上面的那个类,如果你查阅一些资料,很容易就会搞明白,那个类大概是在你使用Java中的反射时加载的,所谓反射代码类似如下所示。

Method method = XXX.class.getDeclaredMethod(xx,xx);

method.invoke(target,params);

友情提示一下,反射是Java中最最基础的一个概念,不懂的朋友自己查一下资料。

简单来说,就是通过XXX.class获取到某个类,然后通过geteDeclaredMethod获取到那个类的方法。

这个方法就是一个Method对象,接着通过Method.invoke可以去调用那个类的某个对象的方法,大概就这个意思。

在执行这种反射代码时,JVM会在你反射调用一定次数之后就动态生成一些类,就是我们之前看到的那种莫名其妙的类

下次你再执行反射的时候,就是直接调用这些类的方法,这是JVM的一个底层优化的机制。

看到这里,有的小伙伴是不是有点蒙?

其实这倒无所谓,这段话看的蒙丝毫不影响你进行JVM优化的

你只要记住一个结论:如果你在代码里大量用了类似上面的反射的东西,那么JVM就是会动态的去生成一些类放入Metaspace区域里的。

所以上面看到的那些奇怪的类,就是由于不停的执行反射的代码才生成的,如下图所示。


一度隠された深い悲劇JVMライン分析、調査を覚えて、解決



8、JVM创建的奇怪类有什么玄机?

那么接下来我们就很奇怪一件事情,就是JVM为什么要不停的创建那些奇怪的类然后放入Metaspace中去?

其实这就要从一个点入手来分析一下了,因为上面说的那种JVM自己创建的奇怪的类,他们的Class对象都是SoftReference,也就是软引用的。

大家可千万别说连类的Class是什么都没听说过?简单来说,每个类其实本身自己也是一个对象,就是一个Class对象,一个Class对象就代表了一个类。同时这个Class对象代表的类,可以派生出来很多实例对象。

举例来说,Class Student,这就是一个类,他本身是由一个Class类型的对象表示的。

但是如果你走一个Student student = new Student(),这就是实例化了这个Student类的一个对象,这是一个Student类型的实例对象。

所以我们这里所说的Class对象,就是JVM在发射过程中动态生成的类的Class对象,他们都是SoftReference软引用的。

所谓的软引用,最早我们再一篇文章里说过,正常情况下不会回收,但是如果内存比较紧张的时候就会回收这些对象。

那么SoftReference对象到底在GC的时候要不要回收是通过什么公式来判断的呢?

是如下的一个公式:

clock - timestamp <= freespace * SoftRefLRUPolicyMSPerMB

这个公式的意思就是说,“clock - timestamp”代表了一个软引用对象他有多久没被访问过了,freespace代表JVM中的空闲内存空间,SoftRefLRUPolicyMSPerMB代表每一MB空闲内存空间可以允许SoftReference对象存活多久。

举个例子,假如说现在JVM创建了一大堆的奇怪的类出来,这些类本身的Class对象都是被SoftReference软引用的。

然后现在JVM里的空间内存空间有3000MB,SoftRefLRUPolicyMSPerMB的默认值是1000毫秒,那么就意味着,此时那些奇怪的SoftReference软引用的Class对象,可以存活3000 * 1000 = 3000秒,就是50分钟左右。

当然上面都是举例而已,大家都知道,一般来说发生GC时,其实JVM内部或多或少总有一些空间内存的,所以基本上如果不是快要发生OOM内存溢出了,一般软引用也不会被回收。

所以大家就知道了,按理说JVM应该会随着反射代码的执行,动态的创建一些奇怪的类,他们的Class对象都是软引用的,正常情况下不会被回收,但是也不应该快速增长才对。

9、为什么JVM创建的奇怪的类会不停的变多?

那么究竟为什么JVM创建的那些奇怪的类会不停的变多呢?

原因很简单,因为文章开头那个新手工程师不知道从哪里扒出来了SoftRefLRUPolicyMSPerMB这个JVM启动参数,他直接把这个参数设置为0了。

他想的是,一旦这个参数设置为0,任何软引用对象就可以尽快释放掉,不用留存,尽量给内存释放空间出来,这样不就可以提高内存利用效率了么?

真是想的很傻很天真。

实际上一旦这个参数设置为0之后,直接导致clock - timestamp <= freespace * SoftRefLRUPolicyMSPerMB这个公式的右半边是0,就导致所有的软引用对象,比如JVM生成的那些奇怪的Class对象,刚创建出来就可能被一次Young GC给带着立马回收掉一些。

如下图所示。


一度隠された深い悲劇JVMライン分析、調査を覚えて、解決



比如JVM好不容易给你弄出来100个奇怪的类,结果因为你瞎设置软引用的参数,导致突然一次GC就给你回收掉几十个类

接着JVM在反射代码执行的过程中,就会继续创建这种奇怪的类,在JVM的机制之下,会导致这种奇怪类越来越多。

也许下一次gc又会回收掉一些奇怪的类,但是马上JVM还会继续生成这种类,最终就会导致Metaspace区域被放满了,一旦Metaspace区域被占满了,就会触发Full GC,然后回收掉很多类,接着再次重复上述循环,如下图所示。


一度隠された深い悲劇JVMライン分析、調査を覚えて、解決



其实很多人会有一个疑问,到底为什么软引用的类因为错误的参数设置被快速回收之后,就会导致JVM不停创建更多的新的类呢?

其实大家不用去扣这里的细节,这里有大量的底层JDK源码的实现,异常复杂,要真的说清楚,得好几篇文章才能讲清楚JDK底层源码的这些细节。

大家只要记住这个结论,明白这个道理就好。

10、如何解决这个问题?

虽然底层JDK的一些实现细节我们没分析,但是大致梳理出来了一个思路,大家也很清楚问题所在和原因了

解决方案很简单。在有大量反射代码的场景下,大家只要把

-XX:SoftRefLRUPolicyMSPerMB=0

这个参数设置大一些即可,千万别让一些新手同学设置为0,可以设置个1000,2000,3000,或者5000毫秒,都可以。

この値を大きくし、それは我々がこのパラメータを最適化し、その時点の後、あなたはシステムの安定動作を確認することができ、容易にリサイクルすることはありません自動的にソフト参照を作成するために、JVMの間に反射のいくつかの種類のClassオブジェクトを作ることです。

基本的にはメタスペースメモリフットプリント領域が前後に変動、安定していません。



おすすめ

転載: blog.51cto.com/14480698/2437111