I wrote this test pre-closure. The problem with closures is that they are optimized to retain a pointer to the values of outer temporary variable they use when activated. Thus the BlockClosures forAnyTwoEqualObjects ofDifferentIdentity registeringAnActionAtFinalizationForEachObject all refer to 'hello' pointed by o1 and its copy pointed by o2. In other words, o1 and o2 are not the single pointers to the String 'hello' and its copy. thenForcingFinalizationOfObjects only clean o1 and o2, but omit to clean the closures that still point to 'hello'... Thus, 'hello' is not finalized. One possibility is to also clean the closures pointing to 'hello'. But now the code is tricky... It's aim was to be simple damned :) Nicolas here is a corrected version : testFinalizationOfEquals "self debug: #testFinalizationOfEquals" | finalizationProbe o1 o2 forAnyTwoEqualObjects ofDifferentIdentity registeringAnActionAtFinalizationForEachObject thenForcingFinalizationOfObjects implyBothRegisteredActionsAreExecuted | finalizationProbe := Set new. o1 := 'hello' copy. o2 := 'hello' copy. forAnyTwoEqualObjects := [o1 = o2]. ofDifferentIdentity := [o1 ~~ o2]. registeringAnActionAtFinalizationForEachObject := [ o1 toFinalizeSend: #add: to: finalizationProbe with: 'first object finalized'. o2 toFinalizeSend: #add: to: finalizationProbe with: 'second object finalized']. thenForcingFinalizationOfObjects := [ forAnyTwoEqualObjects := ofDifferentIdentity := registeringAnActionAtFinalizationForEachObject := nil. o1 := o2 := nil. Smalltalk garbageCollect]. implyBothRegisteredActionsAreExecuted := [finalizationProbe size = 2]. self assert: forAnyTwoEqualObjects; assert: ofDifferentIdentity; should: [ registeringAnActionAtFinalizationForEachObject value. thenForcingFinalizationOfObjects value. implyBothRegisteredActionsAreExecuted value].