内容:
-
ケースの背景紹介
-
シーンを促進するための特別な大電力プロバイダー
-
複数のマシンを必要と大きなプロモーション瞬間圧力に耐えましたか?
-
オーダーシステムのピークを推定するために大容量メモリモデルの利用を促進
-
最終的にはメモリがどのように割り当てるには?
-
新世代のガベージコレクションの最適化のひとつ:サバイバーは十分なスペースではありません
-
新世代のガベージコレクションの対象には、古い年に何回脱出した後?
-
どのくらいのオブジェクトを直接歳に?
-
ガベージコレクタを指定することを忘れないでください。
-
今日の質問
1、ケースの背景紹介
いつものように、我々は特定のシナリオ、メモリ使用量のモデル予測システムで皆をもたらすためにどのように最終的に分析するために、次のケースを駆動します。
次に、新しい歳世代、エデン、サバイバーの各領域のメモリサイズの合理的な最適化。
その後、再び秋に回復するオブジェクトの新しい世代に滞在する可能な限り、古い時代に新世代を避けるために、オブジェクトのパラメータを最適化してみてください。
ここで、背景には、電気の供給システム、通常、多くの独立したサブシステムの配備に分かれ、実際の電力供給システムであります
このような商品・システム、オーダーシステム、マーケティングシステム、在庫システム、ストレージシステム、会員システムなどなど
ここではそれ以上の中央にあるオーダーシステム説明するための例として。
(ヒント:あなたはこのケースを食べる前に、あなたは完全に2週間の記事の前に列を理解しておいてください!)
私たちの場合は、あなたが一日あたり億の要求の量にあなたのエネルギープロバイダシステムを計算することができ、彼はアクティブなユーザーの日々の数だろう、金額を要求された電気背景日常の業務システムの数十億のですか?
一般的に、各ユーザは、要求の数百万の量は、約5万人のユーザーの日常生活を必要とし、平均訪問を20回計算します。
だから、そのうち500万ユーザーが日活はブラウジングの多くに来るされ、プロジェクトを継続し、その後、多くの人が注文をするのだろうか?
一日あたり50万のオーダーが存在することになるように、ここでは10%の賃金変換率に基づいて計算することができ、約50万人が、受注の下で毎日になります。
彼は実際には、毎日のピーク期間の4時間に集中することが、それはまた、おそらく毎秒注文の数十あり、平均で50万件の注文を数え、我々は何も言うことはありませんという感じ?
注文の数十の圧力の下で、基本的にメモリ毎秒の新世代の一部によって占有されているJVMにもっと注意を払う必要がないので、すべての新しい世代は、長い時間のためにいっぱいになります。最初のマイナーGCは、ガベージオブジェクトを一掃した後に続いて、メモリは、ほとんど圧力空いているではありません。
シーンを促進するための2、特殊な大型電気プロバイダー
あなたがシーンを促進するために、特殊な大型電気プロバイダを考慮に入れたい場合しかし、私はそうは思いません。
多くの中小ビジネスプラットフォームなので、システム圧力が通常はそれほど大きく、また高すぎると同時実行実際に行い、同時圧力千ものは、第二のピーク圧力です。
あなたは、このような2人の11何かのように、いくつかの大きなプロモーションのシナリオを、発生した場合は、状況が異なっています。
同様のフェスティバルの11ダブル、ゼロと仮定すると、大きなプロモーションを待っている多くの人々が手のショッピングを切るために開始されます、この時間は、大きなプロモーションのわずか10分で開始することができ、瞬間50万件のオーダーになります。
したがって、この時間は、毎秒千件のオーダーに近いがあるだろうし、我々は、メモリの使用モデルの注文システムを分析するために、現場でこの大きなプロモーションのために持っています。
図3は、瞬間的な必要性いくつかのマシンを促進するための大きな圧力に耐えましたか?
だから、注文システムは、複数のマシンを展開する必要がある、一過性の単一の大きなプロモーション時の圧力に耐えたこと?
基本的には3でカウントするように、つまり、各マシンは、単一の抗リクエストあたり300する必要があります。また、これは非常に合理的である、とオーダーシステムの展開は、最も一般的な標準の4コア8Gマシンであることを前提とする必要があります。
マシン自体のCPUとメモリリソースの角度からは、単一の要求あたり300は問題ありません耐えました。
しかし、問題は、このように可能性としてJVMを減らし、限られたメモリリソースの必要性がガベージコレクションを含め、合理的な配分や最適化をJVMを改善するために最適化されることであるGC JVMのできるだけ少ない数のように、フルGCを回避しようと、GC新システムの影響がより困難ピークです。
4、発注システムのピークを推定促進するための大容量メモリモデルを使用して
背景がすべて終了した後、我々はシステムモデルの受注のメモリ使用量を推定する必要があります。
非常に近いの製造に関連し、実際には、注文処理性能や同時実行の両方を推定する単一の要求に応じて、実質的に300秒で処理することができます
要求処理部は、多くのコール・インタフェースを含む、比較的時間がかかるため、実質的に100〜300毎秒単一の要求は同じです。
その後、我々は1キロバイトを推定するために、各オーダーの大きさで行くだろう、ちょうど300注文はメモリのオーバーヘッドの300キロバイトを持っています
10〜20倍の費用がかかり、その後オーダーエントリオブジェクト数は、関連する受注、在庫、プロモーション、クーポンなど他のビジネスオブジェクト、一連のオブジェクト、一般的に単一のターゲットにズームインする必要があります。
さらに、受注に加えて、オーダーシステムは、オーダーの問い合わせなどの他の操作に関連受注の多くを持つことになりますので、振り返ってみるとジョイントは、あなたは大きな推定値を移動し、10倍の量を拡大することができます。
だから、毎秒は、おそらくメモリのオーバーヘッドの* 20 * 10 = 60メガバイトを300KBでしょう。
しかし、第二の後に、300注文処理が終わったので、すべての関連オブジェクトは、その参照が状態を回復させることができる失っている、60メガバイトのオブジェクトはゴミであると考えることができます。
私たちは見て:
5、どのように最終的にメモリを割り当てるには?
我々は、次に、一般的4GにJVMメモリに、残りの部分は、オペレーティングシステムなどを使用することが空いているいくつかのGままになり、4コア8G機があるとし
古い年は1.5Gで、我々は1.5Gの新しい世代に与えることができ、我々は3Gにメモリをヒープことができ、すべてを一度にメモリ不足のマシンで考えてはいけません。
そして、各スレッドのスタックは、Java仮想マシン1Mを持っているので、スレッドの数百人が存在する場合、JVMは数百Mである可能性が高いです
そして、これは基本的にほぼ同じ、永久に代わっ256Mメモリ、4Gのメモリを与えます。
しかし、また、このようなオープン「-XX:HandlePromotionFailure」など、いくつかの必要なパラメータ、設定することを忘れないオプション(この引数に精通していないが、我々は振り返ると列の前の記事を確認することができます)
次のようにJVMパラメータは、次のとおりです。
「-Xms3072M -Xmx3072M -Xmn1536M -Xss1M -XX:PermSizeを= 256M -XX:MaxPermSizeを= 256M -XX:HandlePromotionFailure」
しかし、「-XX:HandlePromotionFailure」それは放棄された後にJDK 1.6で、パラメータ、今一般的に本番環境では、このパラメータを設定しないでください。
JDK 1.6の後、限り決意「スペースあり才」>「新世代の和オブジェクト」、または「スペースあり才」として>「マイナーGCは前年古いオブジェクトの平均サイズに登ります」
これらの2つの条件が1つのマイナーGCは、事前に全GCをトリガすることなく、直接実施することができます満たされています。
だから、あなたはJDK 1.7またはJDK 1.8を使用している場合、実際には、JVMパラメータはバックにとして残っても、もはやパラメータに参加されていません。
「-Xms3072M -Xmx3072M -Xmn1536M -Xss1M -XX:PermSizeを= 256M -XX:MaxPermSizeを= 256M」
このとき、JVMのメモリは、以下に示します。
そして、それは明らかである、システムプログラムの注文システムは、毎秒300件の注文を取り扱う、大きなプロモーション中に走り続け、新世代は、メモリ空間の60メガバイトを占有します
しかし、それはゴミオブジェクトの60メガバイトになります1秒後には、メモリの1.5Gの新世代は、以下に示すように約25秒で、入力されますかかります。
「-XX:HandlePromotionFailure」があるので、25秒後には、今回のマイナーGCを実行されるオプションは、あなたが考えることができるように、メインは「の古い使用可能なスペース」と「前回のマイナーGC古いへを比較することで後にチェックする必要がありますオブジェクトの最初の平均サイズは、」この検査に合格していることを確認することができます。
だから、マイナーGCの実行は、直接、あなたは最後の2番目の要求に加えて、まだ注文を処理しているので、オブジェクトが100MB程度である生き残ることがあり、この時点でので、ご注文は、処理を終えているだろう、オブジェクトの新しい世代のうち、突然99%のすべてを回復することができます。
「-XX:SurvivorRatio」しかし、もしここで問題は、されているデフォルトのパラメータ値が8であるので、この時点新世代エデン面積はメモリの1.2ギガバイト程度を占めるに以下に示すように、各サバイバー領域は、メモリの150メガバイトです。
エデン領域が一杯に1.2ギガバイトマイナーGCが実行されますされるように、これだけマイナーGCとなり、エデンエリアで満たされる約20秒かかります。
GCは、100メガバイトの周りに生きているオブジェクトは、領域S1に配置されます。以下に。
その後、20秒間再び実行し、面積はライブオブジェクトは、図のように、入力するか、100メガバイト-S2領域の周囲にも、再度、ガベージコレクションオブジェクトをエデン、エデンとS1を満たしました。
次のようにこの時点でJVMパラメータは、次のとおりです。
「-Xms3072M -Xmx3072M -Xmn1536M -Xss1M -XX:PermSizeを= 256M -XX:MaxPermSizeを= 256M -XX:SurvivorRatio = 8」
6、新世代のガベージコレクションの最適化の1:サバイバーは十分なスペースではありません
まず、第1の問題は検討する際に最適化されたJVMの間に、あなたが十分にエンドゾーンに見積もり、サバイバーの新しい世代を渡すということですか?
按照上述逻辑,首先每次新生代垃圾回收在100MB左右,有可能会突破150MB,那么岂不是经常会出现Minor GC过后的对象无法放入Survivor中?然后岂不是频繁会让对象进入老年代?
还有,即使Minor GC后的对象少于150MB,但是即使是100MB的对象进入Survivor区,因为这是一批同龄对象,直接超过了Survivor区空间的50%,此时也可能会导致对象进入老年代。
(关于jvm的垃圾回收规则,如果不太清楚,请参加专栏之前的文章)
所以其实按照我们这个模型来说,Survivor区域是明显不足的。
这里其实建议的是调整新生代和老年代的大小,因为这种普通业务系统,明显大部分对象都是短生存周期的,根本不应该频繁进入老年代,也没必要给老年代维持过大的内存空间,首先得先让对象尽量留在新生代里。
所以此时可以考虑把新生代调整为2G,老年代为1G,那么此时Eden为1.6G,每个Survivor为200MB,如下图。
这个时候,Survivor区域变大,就大大降低了新生代GC过后存活对象在Survivor里放不下的问题,或者是同龄对象超过Survivor 50%的问题。
这样就大大降低了新生代对象进入老年代的概率。
此时JVM的参数如下:
“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8”
其实对任何系统,首先类似上文的内存使用模型预估以及合理的分配内存,尽量让每次Minor GC后的对象都留在Survivor里,不要进入老年代,这是你首先要进行优化的一个地方。
7、新生代对象躲过多少次垃圾回收后进入老年代?
大家都知道,除了Minor GC后对象无法放入Survivor会导致一批对象进入老年代之外,还有就是有些对象连续躲过15次垃圾回收后会自动升入老年代。
其实按照上述内存运行模型,基本上20多秒触发一次Minor GC,那么如果按照“-XX:MaxTenuringThreshold”参数的默认值15次来说,你要是连续躲过15次GC,就是一个对象在新生代停留超过了几分钟了,此时他进入老年代也是应该的。
有些博客会说,应该提高这个参数,比如增加到20次,或者30次,其实那种说法根本是不对的
因为你对这个参数考虑必须结合系统的运行模型来说,如果躲过15次GC都几分钟了,一个对象几分钟都不能被回收,说明肯定是系统里类似用@Service、@Controller之类的注解标注的那种需要长期存活的核心业务逻辑组件。
那么他就应该进入老年代,何况这种对象一般很少,一个系统累计起来最多也就几十MB而已。
所以你说你提高“-XX:MaxTenuringThreshold”参数的值,有啥用呢?让这些对象在新生代里多停留几分钟?
因此考虑问题,一定不要人云亦云,要结合运行原理,自己推演和思考,不同的业务系统还都是不一样的。
其实这个参数甚至你都可以降低他的值,比如降低到5次,也就是说一个对象如果躲过5次Minor GC,在新生代里停留超过1分钟了,尽快就让他进入老年代,别在新生代里占着内存了。
总之,对于这个参数务必是结合你的系统具体运行的模型来考虑。
要记住,JVM没有万能的最佳参数,但是有一套通用的分析和优化的方法。
此时JVM参数如下:
“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5”
8、多大的对象直接进入老年代?
另外有一个逻辑是说,大对象可以直接进入老年代 ,因为大对象说明是要长期存活和使用的
比如在JVM里可能会缓存一些数据,这个一般可以结合自己系统中到底有没有创建大对象来决定。
但是一般来说,给他设置个1MB足以,因为一般很少有超过1MB的大对象。如果有,可能是你提前分配了一个大数组、大List之类的东西用来放缓存的数据。
此时JVM参数如下:
“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M”
9、别忘了指定垃圾回收器
同时大家别忘了要指定垃圾回收器,新生代使用ParNew,老年代使用CMS,如下JVM参数 :
“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC”
ParNew垃圾回收器的核心参数,其实就是配套的新生代内存大小、Eden和Survivor的比例
只要你设置合理,避免Minor GC后对象放不下Survivor进入老年代,或者是动态年龄判定之后进入老年代,给新生代里的Survivor充足的空间,那么Minor GC一般就没什么问题。
然后根据你的系统运行模型,合理设置“-XX:MaxTenuringThreshold”,让那些长期存活的对象,抓紧尽快进入老年代,别在新生代里一直待着。
这样基本上一个初步的优化好的JVM参数就结合你的业务出来了。明天我们继续结合案例来分析 老年代的垃圾回收和参数优化方式。