我实施了一些ExternalStrctures(作为" FFI工作的一部分"),对于其中一些我想实现最终化以回收外部存储器。
我试图为此编写一些测试,并且想知道调用#finalize
的一个好方法是改变我用于测试的特定实例的行为。如果可能的话,我不会用支持测试的代码来污染实现。
我认为模拟特定方法和更改特定实例行为通常是一个很好的测试工具。
我知道其他方言可能,并且我过去在使用#doesNotUnderstand
的Squeak中实现了它,但是我想知道是否有'更清洁的方式,可能由VM支持。
有没有办法改变特定实例如何回答Cuis / Squeak / Pharo中的特定消息?
答案 0 :(得分:3)
卢西亚诺给出了这个奇妙的例子:
EllipseMorph copy compile:' defaultColor ^ Color red&#39 ;; new :: openInWorld
邮件主题在这里: http://cuis-smalltalk.org/pipermail/cuis-dev_cuis-smalltalk.org/2016-March/000458.html
答案 1 :(得分:2)
在处理完问题后,我决定进行端到端测试,实际验证资源(我的情况下的内存)是否恢复到系统。我没有使用过实例行为,尽管Luciano和Juan的解决方案(在评论中)非常有趣。这是我用于测试的代码:
testFinalizationReleasesExternalMemory
" WeakArray restartFinalizationProcess "
| handles |
handles := (1 to: 11) collect: [:i |
Smalltalk garbageCollect.
APIStatus create getHandle].
self assert: (handles asSet size) < 11.
在该示例中,#create
使用对外部函数的FFI调用,该函数分配内存并返回指针(名称create
来自外部API):
create
| answer |
answer := ExternalAPI current createStatus.
self finalizationRegistry add: answer.
^ answer
ExternalAPI
这里是FFI接口,#createStatus
是API调用,它为APIStatus
分配内存并返回指向它的指针。
在结束时,我调用恢复内存的API:
delete
self finalizationRegistry remove: self ifAbsent: [].
self library deleteStatus: self.
handle := nil.
#deleteStatus:
再次是释放内存的API调用。
测试假设外部库一旦空闲就重新使用内存,特别是当新分配的块具有与之前相同的大小时。这在今天的大多数情况下都是正确的,但如果不是,那么我希望看到这个测试失败,至少只是为了学习新东西。
测试分配11个外部结构,保存它们的指针,在分配下一个之前让终结机制释放每个结构的内存,然后比较是否有任何指针重复。我不确定为什么我决定使用10个指针作为一个好数字,只有2个就足够了,但内存分配算法有时候很棘手。