Memory leaky ve standardní knihovně Ruby?

Posted by Jan Kubr Wed, 19 Dec 2007 13:05:00 GMT

Při hledání memory leaku v mém programu jsem narazil na to, že leakuje dost pravděpodobně stadardní knihovna Ruby. Pro detekci objektů, které zůstavají v paměti, jsem použil memory leak detektor dike.

[Update: Leaky způsobovala chyba v diku! Více na mém blogu zde.]

require 'rubygems'
require 'dike'
Dike.logfactory './log/'

class Leak

 def http_call
    puts 'making http call'
    url = URI.parse('http://www.google.com')
    Net::HTTP.start(url.host) do |http|
        puts http.get('/').code
    end
    ''
 end
end

5.times {
    leak = Leak.new
    leak.http_call
    GC.start
    Dike.finger
}

V tomto případě leakuje metoda get, zanechává Net::HTTPFound (HTTPResponse) objekty v paměti. Zaměnění get za request_get leak odstraní.

require 'rubygems'
require 'dike'
Dike.logfactory './log/'

class Leak

  def http_call
    url = URI.parse('http://www.google.com')
    puts 'making the call'
    Net::HTTP.start(url.host) {|http|
        http.request_get('/') do |response|
            response.read_body do |segment|
            end
        end
    }
    return ''
  end
end

5.times {
    leak = Leak.new
    leak.http_call
    GC.start
    Dike.finger
}

V tomto příkladě metoda read_body zanechává v paměti ReadAdapter objekty a kvůli nim tam pak zůstanou i další. Tento problém nastává pouze v případě, že se metodě předá blok. Jinak se ReadAdapter objekt nevytváří a žádný memory leak nenastává.

Nevidím na první, druhý, ani třetí pohled v uvedených příkladech nic podezřelého. Ve zdrojácích knihovny mě také do očí nic nepraštilo. Nic zajímavého jsem ani nevygooglil. Někdo je schopen mi tuhle věc objasnit (co, Davide?:). Další zastávkou bude Ruby mailing list.

Btw,

ruby leak.rb && dike log

2 comments | Tags , , | atom

Comments

Leave a response

  1. Avatar
    David Majda
    about 24 hours later:

    Myslím že nejde o leak v knihovně, ale v samotném jádru Ruby. Věta "Tento problém nastává pouze v případě, že se metodě předá blok." napovídá, že příčina bude nejspíš v zacházení s bloky jakožto uzávěry.

    Při vytvoření bloku se totiž zkopíruje aktuální hodnota self, tabulka lokálních proměnných a další věci, aby je mohl při svém vyvolání (které může nastat o mnoho později a z úplně jiného kontextu, než byl blok definován) blok "vidět". Tím pádem se tyto věci z paměti neodstraní hned po skončení jejich platnosti, ale visí tam do doby, než je uvolněn příslušný blok. Tipnul bych si, že někde bude bug, kdy se některá z těchto věcí v určité situaci zapomene při uvolňování bloku uvolnit s ním, případně že funguje nějak blbě uvolňování bloků samotné.

    V ruby-core mailing listu se nějaké problémy s leaky řešily, ale zda to byla přesně tahle situace, nevím. Stálo by asi za to zkusit aktuální trunk 1.9 a pokud to bude leakovat i tam, reportovat problém do ruby-core.

  2. Avatar
    jan
    14 days later:
    Diky za reakci. Konecne jsem se dokopal k uprave dike, aby fungoval s 1.9 (napr. metoda instance_methods vraci ted pole symbolu a ne retezcu, jako v 1.8) a spustil priklady znovu. Tentokrat leakujou hlavne Stringy a upravy, ktere v 1.8 problemy odstranily, uz nezabiraji. Tj. to bude neco trochu vetsiho, nekdy se na to podivam zas.

Leave a comment