gpt4 book ai didi

ruby - 为什么这个未使用的字符串没有被垃圾收集?

转载 作者:数据小太阳 更新时间:2023-10-29 07:27:23 25 4
gpt4 key购买 nike

为什么 unused_variable_2 和 unused_variable_3 会被垃圾回收,而 unused_variable_1 却不会?

# leaky_boat.rb
require "memprof"

class Boat
def initialize(string)
unused_variable1 = string[0...100]
puts unused_variable1.object_id
@string = string
puts @string.object_id
end
end

class Rocket
def initialize(string)
unused_variable_2 = string.dup
puts unused_variable_2.object_id
unused_variable_3 = String.new(string)
puts unused_variable_3.object_id
@string = string
puts @string.object_id
end
end

Memprof.start

text = "a" * 100
object_id_message = "Object ids of unused_variable_1, @string, unused_variable_2, unused_variable_3, and another @string"
before_gc_message = "Before GC"
after_gc_message = "After GC"
puts object_id_message
boat = Boat.new(text)
rocket = Rocket.new(text)
puts before_gc_message
Memprof.stats
ObjectSpace.garbage_collect
puts after_gc_message
Memprof.stats
Memprof.stop

运行程序:

$ uname -a
Linux [redacted] 3.2.0-25-generic #40-Ubuntu SMP Wed May 23 20:30:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
$ ruby --version # Have to use Ruby 1.8 - memprof doesn't work on 1.9
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
$ ruby -rubygems leaky_boat.rb
Object ids of unused_variable_1, @string, unused_variable_2, unused_variable_3, and another @string
70178323299180
70178323299320
70178323299100
70178323299060
70178323299320
Before GC
2 leaky_boat.rb:6:String
2 leaky_boat.rb:26:String
1 leaky_boat.rb:9:String
1 leaky_boat.rb:7:String
1 leaky_boat.rb:32:Rocket
1 leaky_boat.rb:31:Boat
1 leaky_boat.rb:29:String
1 leaky_boat.rb:28:String
1 leaky_boat.rb:27:String
1 leaky_boat.rb:20:String
1 leaky_boat.rb:18:String
1 leaky_boat.rb:17:String
1 leaky_boat.rb:16:String
1 leaky_boat.rb:15:String
After GC
1 leaky_boat.rb:6:String
1 leaky_boat.rb:32:Rocket
1 leaky_boat.rb:31:Boat
1 leaky_boat.rb:29:String
1 leaky_boat.rb:28:String
1 leaky_boat.rb:27:String
1 leaky_boat.rb:26:String

最佳答案

此行为是因为您的 ruby​​ 版本的 substr 的字符串实现有一个特殊情况来保存内存分配,当您采用作为源字符串尾部的 substr 并且字符串长度足够大而无法存储字符串时基础对象结构中的值。

如果跟踪代码,您会看到范围下标 string[0...100] 将经过 this clause in rb_str_substr .所以新字符串将通过 str_new3 分配。它分配一个新的对象结构(因此不同的 object_id),但是将字符串值 ptr 字段设置为指向源对象的扩展存储的指针,并设置 ELTS_SHARED 标志以指示新对象与另一个对象共享存储空间。

在您的代码中,您获取这个新的子字符串对象并将其分配给实例 var @string,当您运行垃圾回收时,它仍然是一个实时引用。由于存在对原始字符串的已分配存储空间的实时引用,因此无法收集。

在 ruby​​ trunk 中,这种在兼容的尾子字符串上共享存储的优化似乎仍然存在。

另外两个变量 unused_variable_2unused_variable_3 没有这个扩展的存储共享问题,因为它们是通过确保不同存储的机制设置的,所以它们会被垃圾收集正如预期的那样,当它们的引用超出范围时。

String#dup 运行 rb_str_replace (通过 initialize_copy binding )用源字符串内容的副本替换源字符串的内容,并确保不共享存储。

String#new(source_str) 贯穿rb_str_init这同样确保在提供的初始值上使用 rb_str_replace 进行不同的存储。

关于ruby - 为什么这个未使用的字符串没有被垃圾收集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11030139/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com