By Ramon Leon - 31 October 2006 under Smalltalk
Something I've learned since I've become a Smalltalker, is that to live in an image, one must learn to maintain the image.
I used to keep a fresh image handy and whenever things got out of whack, I'd just start over in a new image. I did this out of ignorance; I wasn't aware of how to keep one image from collecting cruft. I'd end up with a ton of obsolete classes that I didn't have a clue how to get rid of, or even understand how they came to be.
This happened a lot when I'd load or unload Monticello packages I'd created, usually due to hidden dependencies between packages. Eventually I learned to package my code better, and found a patch for Monticello that made dependencies actually work the way I expected them to.
I also learned about a great little tool called the PointerFinder from someone on Squeak-Dev, with which I could find all references to an object allowing me to hunt down and clean up bad refs, ridding myself of all those obsolete classes that would accumulate over time. This also taught me how those references came to be, and why they couldn't be cleaned up automatically. This one tool finally allowed me to live in one image and just keep it clean, I rarely if ever need to start from a fresh image any more.
Ultimately, I developed my own version of #garbageCollect that I tossed into a utility class to help me maintain my image. Whenever I find some new maintenance tip to help keep my image clean and organized, I just toss it in here. The last few lines are the most interesting, either everything goes well and the image is saved, or obsolete classes are found and a PointerFinder is launched on each one forcing me to clean up those bad references right away.
Here's what I've collected so far...
garbageCollect | tasks | tasks := OrderedCollection new add: [MCFileBasedRepository flushAllCaches]; add: [WARegistry clearAllHandlers]; add: [SMSqueakMap default clearCaches]; add: [Smalltalk removeEmptyMessageCategories]; add: [Workspace allSubInstancesDo: [:each | each setBindings: Dictionary new]]; add: [Undeclared removeUnreferencedKeys]; add: [Categorizer sortAllCategories]; add: [ODBCConnection cleanAll]; add: [Symbol compactSymbolTable]; add: [ReleaseBuilderDeveloper new fixObsoleteReferences]; add: [Smalltalk garbageCollectMost]; yourself. Utilities informUserDuring: [:bar | tasks do: [:block | bar value: block printString. [block value] on: Error do: [:error | Transcript show: error; cr]]]. SystemNavigation default obsoleteClasses isEmpty ifTrue: [SmalltalkImage current saveSession] ifFalse: [SystemNavigation default obsoleteClasses do: [:each | [PointerFinder on: each] on: Error do: [:error | Transcript show: error; cr]]]
Hopefully the code speaks for itself, and you can remove anything that doesn't apply to your image. If you have any new tips that I'm unaware of, I'd love to hear about them. I'm always looking for a new trick!
I have this wired up to a hot key via KeyBinder, and simply run it once in a while to ensure everything stays nice and clean, and the image organized and small.