ヒープ細分化、プロセスサイズ削減パッチを作った

what this

Heapをこまめにfreeしてやりたいというパッチ
Rubyのプロセス省メモリ化に役立つもの
 

why

今までのHeap管理は足りなくなれば前回付け足したHeapの1.8倍をmallocで確保して使用していた。
しかし、オブジェクトのフラグメントが発生すると中々解放されない。
贅沢にメモリを確保しすぎる傾向にあった。
 

attack plan

  • 一度にmallocするHeapサイズを32KBに決め、複数割り当てる
    • 32KBという根拠はbenchmarkでバランスがよかった
    • バランスとは解放されるHeap数と速度のバランス
  • freeを開始するのは全体の65%にmarkが付いていない場合のみ
    • 65%という数字も経験則によるもの
  • add_heapはrb_new_objの際にインクリメンタルに行う
    • どうせmallocを分割して行うなら、インクリメンタルにやろうということ
  • heapをfreeした場合、次にadd_heapするobject数は現在のobject数の合計
    • これは現在の1.8倍に沿ったもので、前回のadd_heapの1.8倍は現在の合計object数の近似値になることから

 

benchmark

  data    diff 
  Normal  heap_32KB_fix  heap_32KB_fix 
bm_app_pentomino.rb       
gc call   1434  1579  110.11% 
gc all time   375.56  385.52  102.65% 
gc ave time   0.26  0.24  92.31% 
gc min time   0.11  0.06  54.55% 
gc max time   0.52  0.65  125% 
heap ave size   28000  26184  93.51% 
heap max size   28000  26194  93.55% 
heap fin size   28000  26194  93.55% 
program time(sec)   42.5  42.51  100.02% 
       
bm_eval.rb       
gc call   61  71  116.39% 
gc all time   23.47  26.19  111.59% 
gc ave time   0.38  0.37  97.37% 
gc min time   0.07  0.05  71.43% 
gc max time   0.53  0.54  101.89% 
heap ave size   59868  56246  93.95% 
heap max size   60400  57307  94.88% 
heap fin size   60400  57307  94.88% 
program time   1.3  1.32  101.54% 
       
bm_flagment.rb       
gc call   20  19  95% 
gc all time   442.09  294.78  66.68% 
gc ave time   22.1  15.51  70.18% 
gc min time   0.07  0.05  71.43% 
gc max time   51.58  36.11  70.01% 
heap ave size   7885214  4669123  59.21% 
heap max size   18005304  10574675  58.73% 
heap fin size   18005304  10088428  56.03% 
program time   34.27  33.79  98.6% 
       
bm_heapsort.rb       
gc call   22  26  118.18% 
gc all time   2.58  2.7  104.65% 
gc ave time   0.12  0.1  83.33% 
gc min time   0.07  0.05  71.43% 
gc max time   0.21  0.15  71.43% 
heap ave size   28000  24117  86.13% 
heap max size   28000  26195  93.55% 
heap fin size   28000  24558  87.71% 
program time   0.52  0.5  96.15% 
       
bm_life.rb       
gc call   39  43  110.26% 
gc all time   7.91  6.81  86.09% 
gc ave time   0.2  0.16  80% 
gc min time   0.17  0.07  41.18% 
gc max time   0.72  0.21  29.17% 
heap ave size   28000  25853  92.33% 
heap max size   28000  26196  93.56% 
heap fin size   28000  26196  93.56% 
program time   0.52  0.52  100% 
       
bm_mapsort.rb       
gc call   34  41  120.59% 
gc all time   4.07  4.57  112.29% 
gc ave time   0.12  0.11  91.67% 
gc min time   0.07  0.05  71.43% 
gc max time   0.16  0.16  100% 
heap ave size   28000  24281  86.72% 
heap max size   28000  26198  93.56% 
heap fin size   28000  24561  87.72% 
program time   0.5  0.48  96% 
       
bm_occur.rb       
gc call   183  219  119.67% 
gc all time   35.16  36.07  102.59% 
gc ave time   0.19  0.16  84.21% 
gc min time   0  0.06   
gc max time   0.32  0.6  187.5% 
heap ave size   28000  24447  87.31% 
heap max size   28000  26197  93.56% 
heap fin size   28000  24560  87.71% 
program time   4.41  4.34  98.41% 
       
bm_so_binary_trees.rb       
gc call   100  119  119% 
gc all time   20.26  22.59  111.5% 
gc ave time   0.2  0.19  95% 
gc min time   0.07  0.05  71.43% 
gc max time   0.57  0.47  82.46% 
heap ave size   30566  27917  91.33% 
heap max size   60400  57307  94.88% 
heap fin size   60400  57307  94.88% 
program time   1.18  1.2  101.69% 
       
bm_so_count_words.rb       
gc call   15  15  100% 
gc all time   1.24  1.05  84.68% 
gc ave time   0.08  0.07  87.5% 
gc min time   0.08  0.07  87.5% 
gc max time   0.1  0.09  90% 
heap ave size   28002  11461  40.93% 
heap max size   28002  11461  40.93% 
heap fin size   28002  11461  40.93% 
program time   6.19  6.08  98.22% 
       
bm_so_fasta.rb       
gc call   701  770  109.84% 
gc all time   49.1  54.19  110.37% 
gc ave time   0.07  0.07  100% 
gc min time   0  0.06   
gc max time   0.17  0.27  158.82% 
heap ave size   27960  26107  93.37% 
heap max size   28000  26195  93.55% 
heap fin size   28000  26195  93.55% 
program time   5.82  5.93  101.89% 
       
bm_so_nsieve_bits.rb       
gc call   544  653  120.04% 
gc all time   34.24  41.96  122.55% 
gc ave time   0.06  0.06  100% 
gc min time   0.06  0.05  83.33% 
gc max time   0.12  0.51  425% 
heap ave size   28002  24541  87.64% 
heap max size   28002  26196  93.55% 
heap fin size   28002  24559  87.7% 
program time   7.92  8.4  106.06% 
       
bm_so_partial_sums.rb       
gc call   4259  5117  120.15% 
gc all time   218.29  255.5  117.05% 
gc ave time   0.05  0.05  100% 
gc min time   0.05  0.04  80% 
gc max time   0.54  0.46  85.19% 
heap ave size   28000  24556  87.7% 
heap max size   28000  26196  93.56% 
heap fin size   28000  24559  87.71% 
program time   10.36  10.99  106.08% 
       
bm_so_pidigits.rb       
gc call   264  264  100% 
gc all time   24.85  25.2  101.41% 
gc ave time   0.09  0.1  111.11% 
gc min time   0.07  0.06  85.71% 
gc max time   0.3  0.28  93.33% 
heap ave size   28002  26139  93.35% 
heap max size   28002  26195  93.55% 
heap fin size   28002  26195  93.55% 
program time   5.06  5.01  99.01% 
       
bm_so_spectralnorm.rb       
gc call   2101  2321  110.47% 
gc all time   224.35  234.42  104.49% 
gc ave time   0.11  0.1  90.91% 
gc min time   0.07  0.05  71.43% 
heap ave size   28002  26187  93.52% 
heap max size   28002  26194  93.54% 
heap fin size   28002  26194  93.54% 
program time   10.41  10.17  97.69% 

 

result

ほとんどのbenchmarkでheap領域の削減に成功した。
だが、heapサイズが小さくなる分若干スループットが増加した。
 

after

色んなオブジェクトの動きをするベンチマークで試さなければならないし、
Railsなんか動かして本当にプロセスサイズが小さくなるか試してみないといけない。
(でも、Rails触ったことないしなぁ。。。orz)
誰かしてくれませんか。。。といいつつやっぱり自分でするしかなさそう。
このときは凄く遅くなって使い物にならないよとかのFeedbackも貰えるとうれしいな(コード付き)
 

追記

私の使っているプログラムでも試してみたいのですが、gc timeやheap sizeなんかの統計情報はどうやって得るのでしょうか?

 
gc_timeなどの情報はベンチ用にコードに組み込んで取得しています。
統計はrubyでまとめて表示するようなものを作りました。
rb_mem_less_debug_r_15844.diff
gc_prof.rb
ベンチマーク用のコードを処理系に入れるのは少し抵抗感があり入れていません。
少し手間ですが、試して頂けると嬉しい限りです。m(_ _)m