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 还没初始化
method_missing
#1 楼 @huacnlee 感谢回复 :) 我在 app 启动初始化的时候,就已经调用setup方法了,中途也可以正常调用 @redis, 但一段时间后,@redis就 uninitialized class variable 了~
setup
uninitialized 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', 然后刷新网页,此时 @redis 就 uninitialized class variable 。
p 'hello'
#3 楼 @gihnius 在类方法内定义的 @redis, 并不是实例变量,而是属于类的实例变量 .
#3 楼 @gihnius @huacnlee
问题明了。
我的 Redis.setup方法是这么调用的:
Redis.setup
# /config/initializers/redis_cli.rb RedisCli.setup
而一旦我直接在controller中修改任意代码,刷新网页,此时服务器会 reload, 清除掉已定义的类、类变量、类实例变量等。然后重新执行定义类以及其他东西,但是并不会去初始化执行config/initializers下的代码,因此 此时 @redis 为未定义了。
controller
config/initializers
@linjunzhugg 嗯,这是 Rails Reload 的机制,你应该把整个代码放在 initializers 里或者 lib 里。
我还是把我 blog 复制过来吧。https://ruby-china.org/topics/25790
在 Ruby 中一个对象一旦被全局对象引用,它就不会被垃圾回收。这一原则也适用于常量,全局变量,模块 (modules) 和类 (class)。
类变量会被回收。
#9 楼 @victor 类变量不是被类引用吗?
#10 楼 @rei 是的,我那句说错了,正确的应该是:类变量 不会 被回收。