しかし、ビデオとスライドから私が編集した、カットの下にあるイラスト入りの記事の転写の70Kテキストを見てみることもお勧めします。

レポートは実際の経験に基づいており、10年以上にわたり、1秒あたり数百万の見積もり、何万人ものユーザーがオンラインで、大量のデータを扱う非常に負荷の高い複雑な金融アプリケーションを作成してきました。アプリケーションのプロファイリング。


しかし、実際には、まず、サードパーティのツールに問題がある可能性があります。 単に何らかの理由で-信頼性またはセキュリティは、ある種の生活環境でサードパーティのツールを実行できない場合があります。 そして残念なことに、テストプラットフォームだけでなく、ライブプラットフォームでもプロファイリングを行うことが必要になることがよくあります。常に負荷の高いプラットフォームでは、システムの同一のコピーを作成して同じ負荷で実行する機会とリソースがあります。 また、多くのボトルネックは、非常に特定の条件下でのみ、高負荷の下でのみ明らかにできます。 システムが正常に動作していないことがわかりますが、その理由はわかりません。 そのためにどのような負荷パターンを作成する必要がありますか。その結果、問題が明らかになります。したがって、多くの場合、稼働中のシステムのプロファイルを作成する必要があります。
金融アプリケーションを作成するとき、システムの信頼性を確保するタスクがまだあります。 そして、私たちは「銀行」をしません。そこでは、主なことはあなたのお金を失うことではありませんが、何時間も利用できないかもしれません。 システムの可用性が常に24×7であるオンライン取引用の仲介システムを作成します。これはその重要な品質の1つであり、決して低下することはありません。
そして、業界全体が規制されており、実際のシステムでサードパーティ製品を使用できない場合があることも既に述べました。
しかし、ツールはしばしば不透明です。 はい、「何」を説明するドキュメントがありますが、彼がこれらの結果をどのように取得するかについては説明していません。
そして、ツールがオープンソースであっても、何も変更しません。このコードがたくさんあるので、それを理解するのに多くの時間を費やすことになります。 ツールを習得する必要があります。もちろん、自分で何かをすることの方がはるかに楽しいです。

また、たとえば月に1回、パフォーマンスバグのプロファイリングを行う必要があるなど、月に1回何かを行う必要がある場合、適切なツールを学習することで成果を上げることはできません。 もちろん、ツールが何倍も速く問題を解決する状況がない場合。
自分の手で何かをすることで、知識を再利用できます。 たとえば、プログラミング言語やツールの知識がある場合、新しいツールを学習するのではなく、既存のツールを学習することで、それらを深め、拡張し、明確にすることができます。




Javaには、現在の時刻を返す「currentTimeMillis」という素晴らしい機能があります。 ある場所でそれを測定し、別の場所でそれを測定してから、これが行われた回数、合計時間、最小時間と最大時間などを計算できます。 最も簡単な方法。 最大限のシンプルさと初歩的なDIY。
奇妙なことに、実際には、この方法はうまく機能し、多くの利点をもたらします-高速、便利、効率的だからです。

この意味で、アプリケーション自体をプロファイルするようにプログラムすることは論理的なステップです。 アプリケーションの機能を強化すると、アプリケーションのプロファイリングがその機能の一部になります。 特に、この方法でエンドユーザーが呼び出すビジネスメソッドに定義を配置すると、この情報はエンドユーザーにとっても意味のあるものになります。 何回呼び出されたか、どのメソッドが呼び出されたか、どれだけ時間がかかったかなど。 この場合、このアプローチで収集する情報は完全に管理下にあります。 コール数、最小時間、最大時間、平均カウントを測定でき、ランタイムの分布のヒストグラムを作成し、中央値とパーセンタイルをカウントできます。 この例のように、コード内のさまざまな実行パスをさまざまな方法で追跡できます。この例では、話をしながら何とかしましたが、実行パスに応じて、クエリ結果がキャッシュに入れられた頻度と時間それには、要求がデータベースにクロールされる頻度と、その所要時間がかかりました。


すばらしいテクニックです。サードパーティのツールはなく、Javaのほんの少しのコードです。
メソッドが短く、より頻繁に呼び出される場合はどうすればよいですか?
実際には、「currentTimeMillis」メソッドは高速ではなく、ミリ秒単位でしか測定されないため、このような直接メソッドはもはや適切ではありません。


唯一の実際の解決策は、ネイティブコードを使用することです。x86プロセッサには、プロセッサのクロックサイクル数のカウンタを返すような素晴らしい命令rdtscがあります。 それへの直接アクセスはありません;「rdtsc」を呼び出すCの単一行メソッドを記述し、それをJavaコードにリンクしてJavaから呼び出すことができます。 この呼び出しには100サイクルかかります。1000サイクルまたは2サイクルかかるコードを測定する必要がある場合は、各マシンサイクルを最適化し、「プラスまたはマイナス」、「高速、低速」を理解する必要があります。 「仕事の仕方。 すべてのメジャーを最適化する必要がある場合、これは非常にまれなケースです。
ほとんどの場合、短いコードの一部、より頻繁に呼び出されるコードに関しては、「サンプリング」と呼ばれる別のアプローチを使用します。 何回、何が呼び出されるかを正確に測定する代わりに、プログラムの実行を定期的に分析し、任意の時点で、たとえば1秒に1回、10秒に1回など、プログラムの実行場所を確認します

プログラム内のこのような場所は「ホットスポット」と呼ばれます。 これは常に最適化の優れた候補です。 これはすごい-すべてのスレッドのダンプを取得するための「スレッドダンプ」と呼ばれる組み込み関数があります。 Windowsでは、コンソールでCTRL-Breakを押すことで行われます。Linuxおよび他のUnixでは、これは3番目のシグナル「kill -3」コマンドを送信することで行われます。


複数のスレッドダンプを実行し、スレッドダンプを実行します。 最初のものがキャッチされない場合は、さらに2、3を見てください。 プログラムは、ホットスポットで時間の100%を費やすのではなく、50%を費やすかもしれません。 いくつかのスレッドダンプを作成したら、明らかにこれらのポイントのうち少なくとも1つをホットスポットからコードから取り出し、コードを見つけた場所を目で見てください。

また、Javaで記述する場合、システムはリアルタイムではなく、ナノ秒は重要ではありません。これは、すでに定期的にガベージコレクションなどが発生しているためです。 つまり 100ミリ秒の災害に対して不必要に眠りに落ちるシステムを作成しません。
そして私たちの金融分野でさえ、私たちが書いているシステムのほとんど、人々のために書いています、人々は彼らと一緒に働いています、はい、毎秒何百万もの引用があります、はい、ロボットがありますこれらの引用は、プラスまたはマイナス100ミリ秒で目で気付かない人によって監視されます。 200ミリ秒の間ブレーキがかかっている場合、人は気づくでしょう。すでに人にとって顕著な遅延ですが、100ミリ秒はそうではありません。
したがって、余分な100ミリ秒を心配することはできず、3秒ごとにスレッドダンプを行うことで、稼働中のシステムであっても完全に安全に実行できます。 同時に、スレッドダンプはJavaマシンの一部であり、十分にテストされています。Javaマシンでスレッドダンプを実行しようとすると、悪い結果が発生することは、これまで見たことがありません。
つまり これは、生活システムと作業システムをプロファイリングするための完全に安全なツールです。 その後、スレッドダンプファイルを受け取ったら、それを目で見てみるか、少なくとも統計情報を分析し、少なくとも愚かなことを考慮して、どのメソッドが何回出現したか、スレッドの状態を確認するコードの簡単な部分を書くことができます。


Thread.getAllStackTracesこれにより、スタックトレースに関する情報をプログラムで取得できます。
したがって、プロファイリングをこのアプリケーションの機能部分として統合し、組み込みのプロファイリングを使用してアプリケーションを顧客に配布できます。 したがって、アプリケーションを改善するために分析できる情報の一定の流れが得られます。

したがって、スレッドダンプに行がある場合、これがコードのホットラインであることを意味するものではなく、単にホットポイントに最も近いセーブポイントであることを意味します。 「CTRL-BREAK」を押すと、Javaはすべてのスレッドを「最も近いセーブポイントで停止」するようにストリーミングし、Javaマシンは停止したときにのみ、実行中の状態を分析します。

まず、Javaマシンにはすぐに使えるすばらしい機能があります。 メモリーが何でいっぱいなのか、どのオブジェクトがどのくらいのメモリーを占有しているかのヒストグラムを表示する優れたjmapツールがあります。 これは、何が起こっているのか、メモリがどのように詰まっているのかを概観するのに最適なツールです。
繰り返しますが、プログラムのプロファイルを作成したことがない場合、ほとんどの場合、すぐに問題が見つかり、メモリ使用量をさらに最適化するための食料が手に入ります。

したがって、jmapには特別なオプション「ライブ」があります。これは、ヒストグラムを作成する前にガベージコレクションを行い、使用済みのオブジェクトのみを残し、その後ヒストグラムを作成します。
問題は、すでにこのオプションでは、10ギガバイトのメモリで動作するシステムのガベージコレクションに数十から2秒かかるため、多くのギガバイトのメモリで動作する大規模なライブシステムのプロファイルを作成できないことです。システムは、システムが3秒以上応答しない有限の人々と連携して動作します。実際、人と一緒に働く生命システムを1秒以上停止することは不可能です。たとえ1秒でも人にはすでに気づいていますが、まだ災害ではありませんが、10秒間停止するツールを接続すると、災害になります。したがって、多くの場合、それらのオブジェクトのjmapのリビングシステムに満足する必要があり、一般に、それがゴミであるかどうかは関係ありません。

Javaマシンにメモリを使用して状態をディスクに書き込むように依頼できます。これは非常に便利です。通常、人々は何らかの理由でメモリ消費が終了したときにのみメモリ消費の最適化を開始します。すべてが問題ない場合、プロファイリングに従事する人はいませんが、プログラムがメモリ不足になるとクラッシュし、そのように最適化する方法を考え始めます。したがって、常にこのオプションを有効にしておくと便利です。その後、悪い場合には、Javaマシンがバイナリダンプを書き込みます。バイナリダンプは、ライブシステム上ではなく、ツールを使用して後で分析できます。同時に、このダンプは、「-dump」オプションを使用して、同じjmapでJavaマシンからいつでも取得できますが、これもJavaマシンを長時間停止するため、ライブシステムにはほとんどアクセスできません。する。
聴衆からのコメント:この「HeapDumpOutOfMemory」は、メモリがすでに不足している場合に最適化されるというプロパティがあります。
はい、もちろんです。「HeapDumpOutOfMemory」は非常に便利なオプションであり、「-XX」ですが、これらのオプションを恐れてはいけません。ただし、この「XX」はメガスペシャリティを強調しますが、これらは実験的なオプションではなく、Javaマシンの通常の本番オプションであり、安定性、信頼性、ライブの実際のシステムで使用できます。
これらは実験的なオプションではありません! Javaマシンには明確な区分がありますが、実験的および非実験的オプションへの区分はXの数に依存しません。
聴衆からのコメント:ダンプはこのオプションを延期しない場合があります...
まあ、Javaマシンにもバグがあります、それはすべて依存しています...メモリが不足する理由はさまざまです。

それは一つのことです-メモリが何であるか、あなたがそれを使用する方法。コードのどこかに一時メモリの過剰な割り当てがある場合、つまりあなたはそれを分離します...それで何かをします、このメソッドはそれを忘れて、ガベージに入り、ガベージコレクタがそれを拾いますそして、何度も何度もそれを行うと、プログラムはこれで動作するよりも遅くなります...しかし、Javaメモリマシンの割り当て操作は素晴らしく速く、速く動作するため、CPUプロファイラでこのコードの場所は見つかりませんJavaでは、メモリの割り当ては単一のポインタをインクリメントするのに簡単なので、非管理言語であるC / C ++よりも。それだけですこれらはいくつかの組み立て手順であり、すべてが非常に迅速に行われます。すでにゼロにリセットされており、すべてがすでに割り当てられ準備されています。コードのホットスポットを分析する場合、今回は見つかりません。スレッドダンプやプロファイラーで、ホットスポットであることは決して表示されません。それはすべてあなたと一緒ですが、あなたの時間を使い果たしてしまいます、なぜあなたのアプリケーションですか?そのため、ガベージコレクタはこのガベージを収集するために時間を費やします。したがって、アプリケーションがガベージコレクションに費やす時間の割合を調べてください。
これは便利なオプション「-verbose:gc」、「+ PrintGC」、「+ PrintGCDetails」であり、アプリケーションがガベージコレクションに費やす時間を把握できます。時間のかなりの部分がガベージコレクションに費やされていることがわかった場合、プログラムのどこかに多くのメモリを割り当てると、この場所が見つからないため、誰がメモリを割り当てるかを探す必要があります。

これが本当に頻繁に発生する場合は、非常に頻繁に目立つ一時的なクラスがどこかにあることがわかります。すぐにaprofを作成してください-すぐに問題が見つかるかもしれません。

疑いがあるかもしれないことは明らかです-どこで。おそらく最近の変更が行われる可能性があります。最終的に、atomis longでコードを変更する同じ手法を使用して、メモリが頻繁に割り当てられる場所に追加し、この場所で割り当てが行われる回数をカウントします-統計を見て、疑わしい場所を自分で開始して見つけることができます。
しかし、これがどこで起こっているのかわからない場合はどうでしょうか?さて、メモリが割り当てられているすべての場所で、どこかで統計のコレクションを追加する必要があります。アスペクト指向プログラミング、またはバイトコード操作の直接使用は、この種のタスクに最適です。
残りの時間は、バイトコード操作手法に焦点を当てます。これは、「今、この場所で、これがすべての場所で発生する回数を計算したい」などの問題を解決するのにちょうどいい方法です。何らかの理由で多くのint配列を割り当てるまさにその場所を見つけるためのコード。」つまりそれらの多くが際立っていることがわかりますが、私はどこで見つけたいだけです。

そして、これは、コードレイアウトのポストコンパイルとコードの両方で実行できます。

ASMは非常に単純です。彼は.classファイルを読み取り、Visitorテンプレートを使用してバイトを「メソッドを見る」、「このクラスにそのようなフィールドを持つフィールドを見る」などの一連の呼び出しに変換するclass-readerというクラスを持っています。さらに。メソッドを見ると、MethodVisitorを使用して、そこにどんなバイトコードがあるかを報告します。
そして、反対に、クラスをバイトアレイに変換する「ClassWriter」などがありますが、これはJavaマシンに必要です。

そして、メソッド内で、配列割り当てのバイトコード(「NEWARRAY」)を持つ整数命令があることを彼に伝えると、その瞬間、彼は自分のバイトコードを上流に挿入する機会があります。そして、配列が割り当てられているすべての場所を追跡し、対応するバイトコードを変更しました。

コンパイルされたクラスのセットがある場合、それは簡単です→このツールを処理したので、それだけです。
オンザフライでこれを行う必要がある場合は、Javaマシンに素晴らしいオプション-javaagentがあります。マニフェストでオプション「Premain-Class」を指定する特別なjarファイルを作成し、そこにクラスの名前を指定します。次に...特定のテンプレートによる「premain」メソッド。したがって、mainメソッドを使用してメインコードを実行する前であっても、制御を取得し、インターフェイスインスツルメンテーションへのポインタを取得します。このインターフェースは素晴らしいもので、Javaマシンのクラスをオンザフライで変更できます。これにより、Javaマシンがクラスをロードするたびに呼び出す独自のクラスファイルトランスフォーマーを配置できます。
そして、クラスを置き換えることができます。つまり実際に存在するクラスだけでなく、同じObjectWebASMを使用して、何かを分析し、変更し、それらをオンザフライで置き換える...選択したオブジェクトのサイズを確認できます。
特定の問題を解決する必要がある場合に、ひざのプロファイリングを行うためのすばらしいツール。

そして、私たち自身のメモリプロファイリングツールがあるという事実で終わりますが、これもまた小さいですが、どこに何が割り当てられているかを追跡するツールと呼ぶことは難しく、プログラムをほとんど減速させることなくこれを行います。さらに、商用プロファイラとオープンプロファイラの両方で、メモリ割り当てを追跡する方法も知っていますが、より複雑で普遍的な問題を解決しようとしています。彼らは、完全なスタックトレースでメモリ割り当てが発生する場所を見つけようとしています。これは長い時間で、かなり遅くなります。同じサンプリングを使用しないでください。常に収集されるわけではないため、すべての統計を受信するわけではありません。
ある種の妥協を行います。これは、対象分野では必要ありません。システムのパフォーマンスを分析するときに解決したいタスクがいくつかあります。
次に、質問に回答します(30:06からの質問への回答)。
また、アプリケーション開発者の日からの他のトランスクリプトを視聴したり、トレント([2011]、[2010])を使用した過去の会議からすべてのビデオをダウンロードしたり、http経由でフォルダー全体をダウンロードしたりできます。
ところで、Elizarov会議で講演、ADD-2012のレポートで「データをキャッシュするための最速のハッシュを書きます。」