Bug #11332
closedArrayの操作でcrubyインタプリタのメモリリークが起きる
Description
きしもとです
Array の sort! と、pop または shift の操作を組み合わせると、わずか
ですが ruby インタプリタのメモリリークを引き起こすようです。多数回
繰返すと、どんどん大きくなります。
以下のサンプルを手元の環境(FreeBSD/amd64のruby 2.1.6、ruby 2.2.2、
trunk (r51120) )で試すと、どれもインタプリタのプロセスのメモリ
サイズが大きくなっていきます(最後はメモリを確保できなくなって
落ちる)。
# ObjectSpace.memsize_of_all で調べるとオブジェクトは増えたり
# 大きくなったりはしていません。
# -*- mode:ruby ; coding:utf-8 -*-
def sample rg
	arr = []
	sz = 5 + rg.rand(5)
	i = 0
	while i < sz do
		arr[i] = rg.rand
		i += 1
	end
	until arr.empty? do
		arr.sort!
		arr.pop
		#arr.shift
	end
end
randgen = Random.new 12345
count = 0
while true do
	sample randgen
	if (count += 1) > 1000000 then
		count = 0
		p "GC"
		GC.start
	end
end
        
           Updated by wanabe (_ wanabe) over 10 years ago
          Updated by wanabe (_ wanabe) over 10 years ago
          
          
        
        
      
      - Has duplicate Bug #11333: Arrayの操作でcrubyインタプリタのメモリリークが起きる added
        
           Updated by wanabe (_ wanabe) over 10 years ago
          Updated by wanabe (_ wanabe) over 10 years ago
          
          
        
        
      
      - Has duplicate Bug #11334: Arrayの操作でcrubyインタプリタのメモリリークが起きる added
        
           Updated by wanabe (_ wanabe) over 10 years ago
          Updated by wanabe (_ wanabe) over 10 years ago
          
          
        
        
      
      ruby -e 'loop { [1, 2, 3, 4].tap(&:pop).sort! }' とすると、同じ現象と思われるメモリ増加が確認できました。
(ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14])
loop { [1, 2, 3, 4, 5].tap(&:pop).sort! } でも loop { [1, 2, 3].tap(&:pop).sort! } でもメモリ増加は見られなかったので、
RARRAY_EMBED_FLAG や rb_ary_modify() などが関係あるのかもしれない、という気がします。
        
           Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          
          
        
        
      
      Array#popだけで起きるような気がします。
$ for i in 1 5 10 100 1000 10000; do echo; echo $i; ruby2.2 -r ./test/lib/memory_status.rb -e "puts m0 = Memory::Status.new; 10000.times{[*1..$i].pop}; GC.start; puts m1 = Memory::Status.new; p m1.rss.fdiv(m0.rss)"; done
1
{size:2536062976,rss:7557120}
{size:2536062976,rss:7577600}
1.002710027100271
5
{size:2516140032,rss:7319552}
{size:2517188608,rss:8900608}
1.2160044767767209
10
{size:2519285760,rss:7335936}
{size:2520334336,rss:9162752}
1.2490228922389726
100
{size:2526625792,rss:7458816}
{size:2559131648,rss:22032384}
2.9538714991762767
1000
{size:2518237184,rss:7528448}
{size:2612609024,rss:90443776}
12.013601741022851
10000
{size:2517188608,rss:7331840}
{size:2636726272,rss:140148736}
19.115083798882683
        
           Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          
          
        
        
      
      - Description updated (diff)
        
           Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          
          
        
        
      
      popだけで起きるのはOSXのlibc固有のようでした。
Linuxではたしかに4要素から3要素に減らしたあとでsort!した場合だけのようです。
        
           Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          Updated by nobu (Nobuyoshi Nakada) over 10 years ago
          
          
        
        
      
      - Status changed from Open to Closed
Applied in changeset r51147.
array.c: fix memory leak
- array.c (rb_ary_sort_bang): the original array may not be
 embedded even if a substitution array is embedded, as it is
 embedded when the original array is short enough but not
 embedded. [ruby-dev:49166] [Bug #11332]
        
           Updated by metanest (Makoto Kishimoto) over 10 years ago
          Updated by metanest (Makoto Kishimoto) over 10 years ago
          
          
        
        
      
      rev.51148 で実行して直っていることを確認しました