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) about 7 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) about 7 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.