首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这个未使用的字符串没有被垃圾回收?

为什么这个未使用的字符串没有被垃圾回收?
EN

Stack Overflow用户
提问于 2012-06-14 17:21:30
回答 1查看 631关注 0票数 4

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

代码语言:javascript
复制
# 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

运行程序:

代码语言:javascript
复制
$ 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
EN

回答 1

Stack Overflow用户

发布于 2012-06-15 04:31:46

此行为是因为您的substr版本的ruby的字符串实现有一种特殊情况,可在您采用作为源字符串尾部的子字符串并且字符串长度足够长而不在基本对象结构中存储字符串值时,节省内存分配。

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

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

在ruby主干中,这种共享兼容尾子串存储的优化似乎仍然存在。

另外两个var unused_variable_2unused_variable_3没有这种扩展的存储共享问题,因为它们是通过确保不同存储的机制设置的,所以当它们的引用超出作用域时,它们会像预期的那样得到垃圾回收。

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

String#new(source_str)通过rb_str_init运行,类似地,它使用rb_str_replace对提供的初始值确保不同的存储。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11030139

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档