IDL 究竟在做什么?垃圾回收机制
12201 为本文评分:
暂无评分
IDL 究竟在做什么?垃圾回收机制
匿名作者 2014年10月30日,星期四
在 IDL 8.0 版本中,自动垃圾回收机制被引入到 IDL 语言中。它带来了对 IDL 内存使用进行控制的迫切需求缓解。在 IDL 8.0 之前,如果你运行:
obj = obj_new('MyIDLObject')
obj = obj_new('MyOtherIDLObject')
那么第一个 obj 实例就会“泄漏”,这意味着 IDL 无法再访问该内存,并且在 IDL 重启之前这些内存将无法被使用。这在大型应用程序中尤其糟糕,因为“泄漏”的内存会慢慢消耗机器的所有资源。随着垃圾回收机制的加入,一旦第二次调用发生,第一个对象就会被释放,其使用的内存也会被归还给 IDL。因此在 IDL 8.4 中:
IDL> o = obj_new('MyIDLObject') & help,/heap,/brief
Heap Variables:
# Pointer: 0
# Object : 1
# Bytes Heap Memory: 24
IDL> o = obj_new('MyOtherIDLObject') & help,/heap,/brief
Heap Variables:
# Pointer: 0
# Object : 1
# Bytes Heap Memory: 24
然而,考虑以下例子:
p = plot(/test)
p = plot(randomu(seed,100))
如果你运行这些语句,尽管看起来 IDL 的垃圾回收机制应该已经释放了第一个 p 实例,但两个绘图窗口都将保持打开状态。IDL 没有释放第一个 p 实例的原因在于一种叫做“引用计数”的机制。为了执行垃圾回收,IDL 需要知道用户何时不再能引用一个对象。所以如果你运行:
a = obj_new('MyIDLObject')
b = a
help,/heap
IDL 会打印:
Heap Variables:
# Pointer: 0
# Object : 1
<ObjHeapVar2> refcount=2
STRUCT = -> MYIDLOBJECT Array[1]
refcount 字段告诉你有多少个 IDL 变量指向同一个对象。一旦 refcount 变为 0,IDL 的垃圾回收机制就会释放该对象。
注意: 使用 OBJ_DESTROY 方法时要非常小心。如果我在 b 上调用 OBJ_DESTROY,那么 a 将不再是一个有效的对象。如果你想要释放对某个对象不必要的引用,请将变量设置为 !NULL 或 0,以避免销毁所有其他引用所指向的对象。
让我们回到 PLOT 的例子。在这种情况下,由于窗口仍然打开,IDL 将 refcount 保持在零以上。在你关闭窗口之前,绘图对象将保持活动状态。你可能会问自己:“好吧,既然 IDL 拥有这个窗口,我该如何重新获取对它的引用呢?因为我真的不是有意丢失我之前对它的引用。”这时 GETWINDOWS() 和 WINDOW(/current) 就派上用场了。假设你运行了以下代码:
p = plot(/test)
p = plot(randomu(seed,100))
哎呀,我们不想丢失对第一个绘图对象的引用!要找回那个引用:首先,点击那个窗口,然后运行:
w = WINDOW(/current)
接着,在窗口内选中绘图对象并运行:
p1 = w.getselect()
help, p1
P1 PLOT <5168>
第一行获取活动窗口的引用。第二行获取绘图对象的引用。类似地,你也可以在不点击任何东西的情况下,使用 GETWINDOWS() 来获取绘图对象的引用:
pwin = GETWINDOWS()
这将返回一个按创建顺序排列的、对所有活动绘图窗口的引用数组。通过索引到所需的窗口,我们可以通过以下方式获取绘图对象的引用:
tool = pwin[0].gettool()
id = igetid('plot',tool=tool)
obj = tool->getbyidentifier(id)
obj->idlitcomponent::getproperty, _proxy=p1
help, p1
P1 PLOT <5168>
通过理解 IDL 对象的生命周期,你可以更好地管理 IDL 使用的内存,并找回那些你可能认为已经丢失的对象。