Rubyのヒープをビジュアル表示する(翻訳)

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: Visualizing Your Ruby Heap 原文公開日: 2017/09/27 著者: Aaron Patterson サイト: http://tenderlovemaking.com/ Rubyのヒープをビジュアル表示する(翻訳) 前回の記事では、Rubyのオブジェクトがどのようにメモリ上に展開されるかについて軽く触れました。そのときの情報を元に、今回はRubyヒープのダンプを取ってそのヒープの配置や断片化をビジュアル表示するプログラムを書くことにします。 Rubyオブジェクトのレイアウトをざっと復習 単なる復習: Rubyオブジェクトは固定幅です。つまり、あらゆるRubyオブジェクトのサイズは同一(40バイト)になります。オブジェクトは実際にはmallocで割り当てられるのではなく、ページの内部に配置されます。 1つのRubyプロセスには多数のページが含まれ、1つのページには多数のオブジェクトが含まれます。 このオブジェクトはどのページに属するのか? 多くのオブジェクトが1つのページに割り当てられます。各ページは214バイト(訳注: 16,384バイト)です。複数のRubyオブジェクトは同時に割り当てられるのではなく、GCが1つのページ(アリーナとも呼ばれます)を割り当てます。 ページのサイズは正確な214バイトではありません。あるページを割り当てるとき、OSのメモリページに沿ってページを配置したいので、mallocのトータルサイズは4 KB(OSのページサイズ)の倍数よりやや小さい値にする必要があります。mallocシステムコールには若干オーバーヘッドがあるため、連続するOSページにRubyのページを隙間なく収納できるよう、実際にmallocするサイズを総量から差し引かなければなりません。paddingに使うサイズはsizeof(size_t) * 5なので、1ページの実際のサイズは(2 ^ 14) – (sizeof(size_t) * 5)になります。 各ページには、ページ情報の一部を含むヘッダが1つずつあります。ヘッダのサイズはsizeof(void *)です。 つまり、1つのページに保存できるRubyオブジェクトの最大サイズは((2 ^ 14) – (sizeof(size_t) * 5) – sizeof(void *)) / 40になります。 1ページあたりのオブジェクト数には上限があるため、1つのRubyオブジェクトのアドレスの下位14ビットにビットマスクを適用し(ページサイズは214バイトなので、言い換えると14ビットシフトして1ビット残ります)、オブジェクトが実際に配置されるページを算出します。そのビットマスクは~0 << 14です。 あるRubyオブジェクトのアドレスが0x7fcc6c845108の場合、バイナリをASCIIアートで表すと以下のようになります。 11111111100110001101100100001000101000100001000 ^———- ページ アドレス … Continue reading Rubyのヒープをビジュアル表示する(翻訳)