Bug #15121
closedMemory Leak on rb_id2name(SYM2ID(sym))
Description
@ohler55 mentioned in https://github.com/ohler55/oj/issues/501 that calling rb_id2name(SYM2ID(sym))
seems to lock symbols in memory but I couldn't find any issue open for that. So I'm just opening one just in case, but pls close if this is a dupe.
I created a sample C extension to reproduce this
#include "extconf.h"
#include <stdlib.h>
#include <stdio.h>
#include <ruby.h>
VALUE
rb_leak_sym(VALUE self, VALUE argument1) {
const char *sym = rb_id2name(SYM2ID(argument1));
return Qnil;
}
void Init_testsym()
{
rb_define_global_function("leak_sym", rb_leak_sym, 1);
}
We can see it leaking memory with this snippet
require "testsym"
require "objspace"
def record_allocation
GC.start
GC.start
puts "Before - Objects count: #{ObjectSpace.each_object.count}"
puts "Before - Symbols count: #{Symbol.all_symbols.size}"
yield
GC.start
GC.start
puts "After - Objects count: #{ObjectSpace.each_object.count}"
puts "After - Symbols count: #{Symbol.all_symbols.size}"
end
def leak_symbols
1_000_000.times.each { |i| leak_sym("string_number_#{i}".to_sym) }
end
record_allocation do
leak_symbols
end
Output:
$ ruby -v test.rb
ruby 2.4.4p296 (2018-03-28 revision 63013) [x86_64-darwin17]
Before - Objects count: 8784
Before - Symbols count: 3063
After - Objects count: 2008786
After - Symbols count: 1003063
Updated by jeremyevans0 (Jeremy Evans) over 5 years ago
I believe this is expected. Once you ask for the ID of a dynamic symbol, Ruby needs to create a real symbol, and once the real symbol is created, it can never be garbage collected.
You can replace your leak_sym
method with the following and observe the same behavior (symbols that appear in ruby code are also real symbols):
def leak_sym(sym)
eval sym.inspect
end
Updated by ko1 (Koichi Sasada) over 5 years ago
- Status changed from Open to Rejected
Yes, it is expected.
We separate all symbols into two categories:
- static symbols: used by method name and so on. They are not GC'ed managed.
- dynamic symbols: created by Ruby program like
str.to_sym
.
Static symbols are used as method name and so on. And SYM2ID()
makes static symbols from dynamic symbols.
This is an implementation limitation and we expect this limitation is appropriate for most of Ruby programs.