Ruby Forum Ruby > Hard question: Any ideas why this code leaks memory?

Posted by Sven C. Koehler (Guest)
on 19.08.2008 21:50
(Received via mailing list)
Hello,

could someone help me understand why this code leaks memory? (I am using
ruby 1.8.6 (2007-12-03 patchlevel 113) [x86_64-linux].)

def rss_leaks
  /^VmRSS:\s+(\d+)/m.match(File.open("/proc/#{$$}/status") {|f|
      f.read })[1].to_i
end

| irb(main):002:0> 100000.times { rss_leaks }; rss_leaks
| => 11624
| irb(main):003:0> 100000.times { rss_leaks }; rss_leaks
| => 16836
| irb(main):004:0> 100000.times { rss_leaks }; rss_leaks
| => 22008
| irb(main):005:0> 100000.times { rss_leaks }; rss_leaks
| => 27248
| irb(main):006:0> 100000.times { rss_leaks }; rss_leaks
| => 32468

Calling GC.start inbetween does not help, but when we rewrote rss_leaks
this way the leaks disappeared:

def rss_no_leaks()
   d = File.open("/proc/#{$$}/status") {|f| f.read }
   /^VmRSS:\s+(\d+)/m.match(d)[1].to_i
end

| irb(main):002:0> 100000.times { rss_no_leaks }; rss_no_leaks
| => 6568
| irb(main):003:0> 100000.times { rss_no_leaks }; rss_no_leaks
| => 6568
| irb(main):004:0> 100000.times { rss_no_leaks }; rss_no_leaks
| => 6588
| irb(main):005:0> 100000.times { rss_no_leaks }; rss_no_leaks
| => 6592
| irb(main):006:0> 100000.times { rss_no_leaks }; rss_no_leaks
| => 6572

Any help to further understand what actually causes these leaks would be
very appreaciated!

Best wishes,

Sven
Posted by Xavier Noria (fxn)
on 20.08.2008 02:32
(Received via mailing list)
On Tue, Aug 19, 2008 at 9:46 PM, Sven C. Koehler <schween@snafu.de> 
wrote:

> def rss_leaks
>  /^VmRSS:\s+(\d+)/m.match(File.open("/proc/#{$$}/status") {|f|
>      f.read })[1].to_i
> end

No idea about the leak, just wanted to point out for the archives that
/m does nothing there because there's no dot.

/m in Ruby is /s in Perl ("." matches "\n"), and Perl's /m (multi-line
mode) is always on in Ruby, there's no way to switch that one off. ^
is always beginning of line, and you assert beginning of string with
\A. To tangle this a little more /s in Ruby exists and means the
regexp is written in the SJIS encoding.
Posted by Nobuyoshi Nakada (nobu)
on 20.08.2008 04:54
(Received via mailing list)
Hi,

At Wed, 20 Aug 2008 04:46:24 +0900,
Sven C. Koehler wrote in [ruby-talk:311847]:
> could someone help me understand why this code leaks memory? (I am using
> ruby 1.8.6 (2007-12-03 patchlevel 113) [x86_64-linux].)
> 
> def rss_leaks
>   /^VmRSS:\s+(\d+)/m.match(File.open("/proc/#{$$}/status") {|f| 
>       f.read })[1].to_i
> end

> Calling GC.start inbetween does not help, but when we rewrote rss_leaks
> this way the leaks disappeared:
> 
> def rss_no_leaks()
>    d = File.open("/proc/#{$$}/status") {|f| f.read }
>    /^VmRSS:\s+(\d+)/m.match(d)[1].to_i
> end

Seems a bug.
Posted by Sven C. Koehler (Guest)
on 20.08.2008 05:54
(Received via mailing list)
On Wed, Aug 20, 2008 at 11:50:16AM +0900, Nobuyoshi Nakada wrote:
> Seems a bug.

Yep, and it seems to be fixed in 1.8.7-p71 :
http://rubyforge.org/tracker/?func=detail&aid=15425&group_id=426&atid=1698

-S.
Posted by Nobuyoshi Nakada (nobu)
on 20.08.2008 08:44
(Received via mailing list)
Hi,

At Wed, 20 Aug 2008 12:49:41 +0900,
Sven C. Koehler wrote in [ruby-talk:311908]:
> Yep, and it seems to be fixed in 1.8.7-p71 :
> http://rubyforge.org/tracker/?func=detail&aid=15425&group_id=426&atid=1698

Hmmm, indeed.  But it seems to occur with the latest 1.8.
Posted by Sven C. Koehler (Guest)
on 20.08.2008 13:24
(Received via mailing list)
On Wed, Aug 20, 2008 at 03:44:15PM +0900, Nobuyoshi Nakada wrote:
> At Wed, 20 Aug 2008 12:49:41 +0900,
> Sven C. Koehler wrote in [ruby-talk:311908]:
> > Yep, and it seems to be fixed in 1.8.7-p71 :
> > http://rubyforge.org/tracker/?func=detail&aid=15425&group_id=426&atid=1698
> 
> Hmmm, indeed.  But it seems to occur with the latest 1.8.

I tried some of the patches mentioned on the page on my ruby-1.8.6, and 
this is
the patch which worked for me (saves me some time before upgrading to 
1.8.7).

-S.

--- parse.old.y 2008-08-20 10:59:56.000000000 +0000
+++ parse.y     2008-08-20 11:08:16.000000000 +0000
@@ -5716,7 +5716,7 @@
                    rb_mem_clear(vars+i, len-i);
                }
                else {
-                   *vars++ = (VALUE)ruby_scope;
+                   *vars++ = 0;
                    rb_mem_clear(vars, len);
                }
                ruby_scope->local_vars = vars;
@@ -5732,6 +5732,7 @@
                if (!(ruby_scope->flags & SCOPE_CLONE))
                    xfree(ruby_scope->local_tbl);
            }
+            ruby_scope->local_vars[-1] = 0; /* no reference needed */
            ruby_scope->local_tbl = local_tbl();
        }
     }
Posted by Nobuyoshi Nakada (nobu)
on 20.08.2008 22:38
(Received via mailing list)
Hi,

At Wed, 20 Aug 2008 20:19:43 +0900,
Sven C. Koehler wrote in [ruby-talk:311956]:
> I tried some of the patches mentioned on the page on my ruby-1.8.6, and this is
> the patch which worked for me (saves me some time before upgrading to 1.8.7).

It has been applied to the latest 1.8, of course.
Posted by Roger Pack (Guest)
on 06.10.2008 20:28
(Received via mailing list)
Issue #461 has been updated by Roger Pack.


You should try SVN HEAD and see if it's still there.
See also 
http://rubyforge.org/tracker/?func=detail&atid=1698&aid=15425&group_id=426
----------------------------------------
http://redmine.ruby-lang.org/issues/show/461