Django メモリプロファイラ:稼働中アプリのメモリ使用状況をオブジェクト単位で分析する
Django アプリのメモリ使用状況をプロファイリングするには、変更を加えていない稼働中の Python プロセスに OpenResty XRay をアタッチするだけです。コードを変更する必要はありません。すると Python GC オブジェクトメモリ分布フレームグラフが生成され、メモリがどこで使われているかを、モジュールのキャッシュ辞書のような個々のオブジェクトのレベルまで正確に示してくれます。このチュートリアルでは、86 MB のメモリを使用する、変更を加えていない Django プロセスを題材に、その分析手順を一つずつ解説します。OpenResty XRay が自動的に推定する詳細なデータ参照パスを通じて、文字列や辞書といった任意の Python オブジェクトを細かく調べることができます。
ps による高メモリ Django プロセスの特定
ps aux | grep python3 を実行して Python プロセスの一覧を表示します。すると 1 つの python3 manage.py runserver プロセスが際立っており、約 86 MB の常駐メモリ(RSS)を使用しています。しかもこれは Linux ディストリビューションに同梱されている標準の /bin/python3 バイナリで、一切変更を加えずに稼働しています。
Guided Analysis による Django アプリのメモリプロファイリング
OpenResty XRay の Web コンソールを開き、対象のマシンが正しく選択されていることを確認してから、Guided Analysis ページに移動します。ここでは OpenResty XRay が診断できる問題の種類から選択できます。
High memory usage を選択し、この Python Django アプリと、ps で見つけた子プロセス(RSS を 84 MB 使用しているもの)を選びます。Python と C/C++ の両方の言語レベルを選択したままにし、デフォルトの 300 秒の上限で分析を開始します。1、2 ラウンドの分析を経ると、OpenResty XRay が自動的にレポートを生成します。Python-Land(Python レベル)の下に、GC オブジェクトメモリ分布で最もホットな第 1 位のデータ参照パスが表示されます。インタープリターの .modules を経由してたどり着く、38.27 MB を占める dict です。
このデータ参照パスは、インタープリターがロードした Python モジュールが合計で 38MB のメモリを使用していることを示しています。
詳細情報を見るには「More」をクリックします。
このデータ参照パスは、この Python GC オブジェクトメモリ分布フレームグラフから自動的に導き出されたものです。
以下は、現在の問題についてのより詳細な説明と提案です。
.modules について言及しています。
そして、これには Python モジュールに関連するすべてのものが含まれていると述べています。
次に、フレームグラフを拡大して、どの Python モジュールが比較的多くのメモリを占有しているかを見つけます。
ここでは 1521 個の Python モジュールがまとめられていることがわかります。各モジュールはメモリの 1% 未満しか使用していません。
このモジュールは比較的多くのメモリを使用しています。クリックして拡大し、より詳細を確認できます。
ここでは、openpyxl.utils.cell モジュールが 2.6MB 以上のメモリを使用していることがわかります。openpyxl は Excel ファイルを処理する Python ライブラリです。
モジュール名をコピーします。
ターミナルを開き、find コマンドを使用して、プロジェクトディレクトリ内でこのモジュールに対応するソースコードファイルを検索します。プロジェクトディレクトリは Python モジュールのインストールパスのルートディレクトリです。
先ほどコピーしたモジュール名を貼り付けます。
ここでは、モジュール名のドットを grep コマンドのワイルドカードとして使用しています。
このファイルパスをコピーします。
vim エディタを使用してソースファイルを開き、このファイル内の Python 実装コードを確認します。お好みのエディタを使用できます。
フレームグラフに戻ります。
openpyxl モジュールは _COL_STRING_CACHE と _STRING_COL_CACHE という 2 つの辞書を定義しています。これらは Excel のセル座標と列名の間の変換に使用されます。これらの変数は比較的多くのメモリを使用しています。
最初の変数の名前をコピーします。
次に _COL_STRING_CACHE を検索すると、このオブジェクトを見つけることができます。このファイル内でこの変数を使用しているすべての場所も見つけることができます。
_STRING_COL_CACHE 変数も同様の方法で見つけることができます。
フレームグラフ上の他のメモリを多く使用しているモジュールも同様の方法で分析できます。
例えば、linecache モジュールです。これはファイルの内容をキャッシュする Python の標準モジュールです。648KB のメモリを使用しています。
cache という名前の変数があり、多くのメモリを使用しています。
Python は Libc アロケータと mmap システムコールを使用してメモリを割り当てています。レポートによると、Libc アロケータは 18.7MB のメモリを使用しています。
Insights による Django メモリ使用状況の自動監視
OpenResty XRay は、稼働中のプロセスを自動的に監視して分析レポートを表示することもできます。Insights ページでは、日次および週次のレポートを確認できます。Guided Analysis を手動で実行しなくても、同じメモリ参照パスと分布が得られます。もっとも、Guided Analysis はアプリケーションの開発やデモンストレーションの用途では引き続き有用です。
よくある質問
コードを変更せずに Django アプリのメモリ使用状況をプロファイリングするには?
すでに稼働している、変更を加えていない Python プロセスに OpenResty XRay をアタッチし、Guided Analysis を開始します。プロセスをリアルタイムで読み取るため、Django アプリを編集したり、計装を仕込んだり、再デプロイしたりする必要はありません。その結果として、メモリがどこで使われているかを個々の Python オブジェクトのレベルまで示すレポートとフレームグラフが得られます。
Django アプリではどの Python モジュールが最もメモリを使いますか?
GC オブジェクトメモリ分布フレームグラフを拡大すると、モジュールをサイズ順に並べられます。この例では、openpyxl.utils.cell モジュールが _COL_STRING_CACHE と _STRING_COL_CACHE の 2 つの辞書で 2.6 MB 以上を占め、標準モジュールの linecache はファイル内容をキャッシュする cache 辞書に 648 KB を保持しています。
Python GC オブジェクトメモリ分布フレームグラフとは何ですか?
これは OpenResty が考案したフレームグラフで、すべての Python ガベージコレクション対象オブジェクトを、それぞれが占めるメモリ量と、どのデータ参照パス上にあるかによって配置します。OpenResty XRay がこれを自動的に生成・解釈するため、ある文字列や辞書を、それを保持しているモジュールまでさかのぼって追跡できます。
小さな Django プロセスがなぜこれほどメモリを使うのですか?
その多くはインタープリター自体によるものです。ロード済み Python モジュールの .modules レジストリが 38 MB を占め(1521 個のモジュールオブジェクトだけでも合計 13.7 MB になります)、さらに openpyxl のキャッシュ辞書のような各モジュールレベルのキャッシュがその上に積み重なります。フレームグラフは 1 MB ごとに具体的なオブジェクトへと帰属させるため、どこを削減する価値があるかを見極められます。
OpenResty XRay について
OpenResty XRay は動的トレーシング製品であり、実行中のアプリケーションを自動的に分析して、パフォーマンスの問題、動作の問題、セキュリティの脆弱性を解決し、実行可能な提案を提供いたします。基盤となる実装において、OpenResty XRay は弊社の Y 言語によって駆動され、Stap+、eBPF+、GDB、ODB など、様々な環境下で複数の異なるランタイムをサポートしております。
著者について
章亦春(Zhang Yichun)は、オープンソースの OpenResty® プロジェクトの創始者であり、OpenResty Inc. の CEO および創業者です。
章亦春(GitHub ID: agentzh)は中国江蘇省生まれで、現在は米国ベイエリアに在住しております。彼は中国における初期のオープンソース技術と文化の提唱者およびリーダーの一人であり、Cloudflare、Yahoo!、Alibaba など、国際的に有名なハイテク企業に勤務した経験があります。「エッジコンピューティング」、「動的トレーシング」、「機械プログラミング」 の先駆者であり、22 年以上のプログラミング経験と 16 年以上のオープンソース経験を持っております。世界中で 4000 万以上のドメイン名を持つユーザーを抱えるオープンソースプロジェクトのリーダーとして、彼は OpenResty® オープンソースプロジェクトをベースに、米国シリコンバレーの中心部にハイテク企業 OpenResty Inc. を設立いたしました。同社の主力製品である OpenResty XRay(動的トレーシング技術を利用した非侵入的な障害分析および排除ツール)と OpenResty Edge(マイクロサービスおよび分散トラフィックに最適化された多機能ゲートウェイソフトウェア)は、世界中の多くの上場企業および大企業から高い評価を得ております。OpenResty 以外にも、章亦春は Linux カーネル、Nginx、LuaJIT、GDB、SystemTap、LLVM、Perl など、複数のオープンソースプロジェクトに累計 100 万行以上のコードを寄与し、60 以上のオープンソースソフトウェアライブラリを執筆しております。
翻訳
英語版の原文と日本語訳版(本文)をご用意しております。読者の皆様による他の言語への翻訳版も歓迎いたします。全文翻訳で省略がなければ、採用を検討させていただきます。心より感謝申し上げます!













































