当我有一个非冻结的非实习字符串时,我可以获取其源位置(假设文件名为foo_file.rb
):
require "objspace"
ObjectSpace.trace_object_allocations_start
obj = "foo"
ObjectSpace.allocation_sourcefile(obj) # => foo_file.rb
ObjectSpace.allocation_sourceline(obj) # => 4
当我有一个实习字符串时,源位置变得不可用(请注意字符串文字后面带有freeze
的实习功能):
obj = "foo".freeze
ObjectSpace.allocation_sourcefile(obj) # => nil
ObjectSpace.allocation_sourceline(obj) # => nil
我可以确认这种不可用性不是因为它被冻结了,而是因为它被实习:
obj = "foo"
obj = obj.freeze
ObjectSpace.allocation_sourcefile(obj) # => foo_file.rb
ObjectSpace.allocation_sourceline(obj) # => 4
为什么我无法从实习字符串中获取源信息?
当我有一个正则表达式时,即使它没有被冻结,我也无法获得源信息:
obj = /foo/
obj.frozen? # => false
ObjectSpace.allocation_sourcefile(obj) # => nil
ObjectSpace.allocation_sourceline(obj) # => nil
为什么我不能从正则表达式获取源位置,即使它没有被冻结?
答案 0 :(得分:2)
在ObjectSpace.trace_object_allocations_start
调用之前简单地分配了这两个对象,或者执行了此文件中的任何其他Ruby代码:
"foo".freeze
已分配到compile time by rb_fstring()
(最初也位于parse time)
在运行时额外分配"foo"
只是因为内部obj = "foo"
实际上与obj = "foo".dup
相似。有关更多详细信息,请查看putstring
YARV instruction和rb_str_resurrect()
函数的定义。
/foo/
已在parse time by reg_compile()
分配。就是这样。这里没有重复,因此它始终是同一个对象(虽然没有实习,但对某些人来说可能是令人惊讶的行为):
3.times.map{ "foo".object_id }.uniq # => [21063740, 21063720, 21063700]
3.times.map{ "foo".freeze.object_id }.uniq # => [21064340]
3.times.map{ /foo/.object_id }.uniq # => [21065100]