在 Ruby 中删除对象
假设我有以下课程:
class Vehicle
@@total_vehicles = 0
@@all_instances = Array.new
def initialize
@@total_vehicles += 1
@@all_instances << self
end
def total_vehicles #returns total number of Vehicles 'alive'
return @@total_vehicles
end
def all_vehicles #returns an array of all Vehicle objects
return @@all_instances
end
end
现在为了使 @@total_vehicles
和 @@all_instances
保持最新且正确,我想确保它们正确递减当这些对象之一被垃圾收集时,分别进行更新和更新。但发生的情况是这样的:
v = Vehicle.new
Vehicle.total_vehicles # => 1
v = nil #no references to Vehicle instance now
ObjectSpace.garbage_collect #instance garbage collected
Vehicle.total_vehicles # => 1 Nope!
我可以向 Vehicle 类的每个实例添加一个终结器 Proc,当调用对象的垃圾回收时,将调用该终结器 Proc。但根据文档,ObjectSpace.define_finalizer(v,someProc)
会在 Vehicle 实例被销毁后调用 someProc - 这意味着我无法使用 self
或 self.class 在那里(因为不会有类,因为没有对象!)我可以让 proc 调用 Vehicle 类上的公共访问器方法,但这剥夺了类变量只能由类访问,并且它的实例 ->本质上是将类变量转换为 gvar。
我如何才能拥有相当于析构函数方法(来自 C++)的功能,该方法可以在垃圾收集之前按顺序获取 Vehicle 实例的事务?
聚苯乙烯 ObjectSpace#count_objects
不是一个可行的选择,因为甚至 Ruby 文档都在前面。
Let's say I have the following class:
class Vehicle
@@total_vehicles = 0
@@all_instances = Array.new
def initialize
@@total_vehicles += 1
@@all_instances << self
end
def total_vehicles #returns total number of Vehicles 'alive'
return @@total_vehicles
end
def all_vehicles #returns an array of all Vehicle objects
return @@all_instances
end
end
Now to keep @@total_vehicles
and @@all_instances
up-to-date and correct, I want to make sure that they are correctly decremented and updated, respectively, when one of those objects is garbage collected. But here is what happens:
v = Vehicle.new
Vehicle.total_vehicles # => 1
v = nil #no references to Vehicle instance now
ObjectSpace.garbage_collect #instance garbage collected
Vehicle.total_vehicles # => 1 Nope!
Well I could add a finalizer Proc to each instance of the Vehicle class that, when called upon the object's garbage collection, would be called. But according to the documentation, ObjectSpace.define_finalizer(v,someProc)
would call someProc after the Vehicle instance is destroyed - meaning I cannot use self
or self.class
in there (since there would be no class, as there is no object!) I could have the proc call a public accessor method on the Vehicle class, but that takes away the purpose of class variables being accessible only to the class and its instances -> essentially turning the class variables into gvars.
How can I have the equivalent of a destructor method (from C++) that will get a Vehicle instance's affairs in order, as it were, before getting garbage-collected?
P.S.ObjectSpace#count_objects
is no a viable option, as even the Ruby docs are up front about.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您几乎肯定想要的是 WeakRef来自标准库的类。它可以处理对象跟踪和管理的所有细节,而不会阻止引用计数。
使用指向跟踪中的对象的 WeakRef,您可以将整个完成工作委托给库,并简化您自己的生活。 (您可能需要从数组中清除死项,但这很容易包装在您的父类中。)
例如:
What you almost certainly want here is the WeakRef class from the standard library. That handles all the details of object tracking and management without blocking reference counting.
Using a WeakRef that points to the object in your tracking you can delegate the whole finalization work to the library, and simplify your own life. (You may need to flush dead items from the arrays, but that is easily enough wrapped in your parent class.)
eg:
现在,它们永远不会被垃圾收集,因为您在
@@all_instances
中持有引用。您可以使用终结器来获得您想要的结果:如果您运行此代码,您将看到它“有效”,只是仍然有一辆车辆未进行垃圾收集。我不知道为什么会这样。
您的
count
方法也可以通过返回ObjectSpace.each_object(Vehicle).count
来更简单地定义。最后,如果您确实想维护现有车辆的列表,则需要存储它们的 ID 并使用
ObjectSpace._id2ref
:Right now, they will never be garbage collected, as you are holding a reference in
@@all_instances
. You could use a finalizer to get the result you want:If you run this code, you will see that it "works", except that there remains one Vehicle that is not garbage collected. I'm not sure why that is.
Your
count
method could be also defined more simply by returningObjectSpace.each_object(Vehicle).count
Finally, if you really want to maintain a list of existing Vehicles, you need to store their ID and use
ObjectSpace._id2ref
: