Ruby 类变量以及类实例变量会被 GC 么?

linjunzhugg · 2015年05月28日 · 最后由 victor 回复于 2015年05月29日 · 2808 次阅读

ruby2.2

写了个类:

class RedisCli

  class << self

    def setup
      @redis ||= Redis.new
    end

    def method_missing(meth, *args, &blk)
      @redis.send(meth, *args,  &blk)
    end

  end
end

这里的 @redis 为类实例变量,按道理应该不会被 GC 才对,但我发现一段时间过后 @redis 就变成未定义了,所以很疑惑。

class RedisCli
  class << self
    def client
      @redis ||= Redis.new
    end

    def method_missing(meth, *args, &blk)
      client.send(meth, *args,  &blk)
    end
  end
end

改成这样,有可能是调用到 method_missing 的时候,@redis 还没初始化

#1 楼 @huacnlee 感谢回复 :) 我在 app 启动初始化的时候,就已经调用setup方法了,中途也可以正常调用 @redis, 但一段时间后,@redisuninitialized class variable 了~

做了下实验:

class RedisCli
  @redis_test = 'test'
  class << self

    def setup
      @redis ||= Redis.new
    end

    def method_missing(meth, *args, &blk)
      @redis.send(meth, *args,  &blk)
    end

  end
end

惊奇的发现: @redis消失了 (确定事先已经调用 setup 方法),但是 @redis_test 这变量还存在着。难道在类方法外跟类方法内定义类实例变量是不同的?

补充下:

ruby2.2 rails4.2

app 初始化后,我不断刷新页面 (会访问到 @redis 变量),此时 @redis 是正常的,直到我随意改动下代码,比如在 controller 中多了个p 'hello', 然后刷新网页,此时 @redisuninitialized class variable

3 楼 已删除

#3 楼 @gihnius 在类方法内定义的 @redis, 并不是实例变量,而是属于类的实例变量 .

5 楼 已删除

#3 楼 @gihnius @huacnlee

问题明了。

我的 Redis.setup方法是这么调用的:

# /config/initializers/redis_cli.rb

RedisCli.setup

而一旦我直接在controller中修改任意代码,刷新网页,此时服务器会 reload, 清除掉已定义的类、类变量、类实例变量等。然后重新执行定义类以及其他东西,但是并不会去初始化执行config/initializers下的代码,因此 此时 @redis 为未定义了。

@linjunzhugg 嗯,这是 Rails Reload 的机制,你应该把整个代码放在 initializers 里或者 lib 里。

8 楼 已删除

我还是把我 blog 复制过来吧。https://ruby-china.org/topics/25790

在 Ruby 中一个对象一旦被全局对象引用,它就不会被垃圾回收。这一原则也适用于常量,全局变量,模块 (modules) 和类 (class)。

类变量会被回收。

#9 楼 @victor 类变量不是被类引用吗?

#10 楼 @rei 是的,我那句说错了,正确的应该是:类变量 不会 被回收。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号