How to explore objects pinned in memory
This page contains scripts and strategies useful for debugging pinned in memory objects.
Pinned in memory objects are normal during the execution. However, if they cannot be garbaged collected, they will lead to an increase in memory size, as they cannot be moved around when compacting memory.
Parameters to FFI calls are pinned in memory. If one of those parameters is a string literal, it will not be garbaged collected.
2 timesRepeat: [ Smalltalk garbageCollect ]. (SystemNavigation default allObjects select: [ :e | e isPinnedInMemory ]) size
Here we just get the string representation as getting the actual objects can create references to it, making it harder to find from where they are referenced
2 timesRepeat: [ Smalltalk garbageCollect ]. (SystemNavigation default allObjects select: [ :e | e isPinnedInMemory ]) collect: [ :each | each printString ]
SystemNavigation default allObjects select: [ :e | e isPinnedInMemory ]
To get accurate results it is best to do a few gargage collects before, so pinned objects that can be gargaged collected are removed.
2 timesRepeat: [ Smalltalk garbageCollect ]. (SystemNavigation default allObjects select: [ :e | e isPinnedInMemory ])
(SystemNavigation default allObjects select: [ :e | e isPinnedInMemory ]) do: [ :e | e unpinInMemory ]
2 timesRepeat: [ Smalltalk garbageCollect ]. pinned := SystemNavigation default allObjects select: [ :each | each isPinnedInMemory ]
pinned size
pinned groupedBy: #className
2 timesRepeat: [ Smalltalk garbageCollect ]. pinnedData := (SystemNavigation default allObjects select: [ :each | each isPinnedInMemory]) collect: [ :each | each class name -> each printString ].
pinnedData groupedBy: #key
We can use ReferenceFinder
to find references to a particular pinned objects.
To get accurate results it is best to do a few garbage collects before, and not store the list of pinned objects in any local variable or inspect it
NOTE: This does not work if the pinned objects is a method literal. So of the list of references to a pinned objects that is not garbage collected is nil, it means that the object is most likely a methid literal.
2 timesRepeat: [ Smalltalk garbageCollect ]. ReferenceFinder findPathTo: ((SystemNavigation default allObjects select: [ :e | e isPinnedInMemory ]) at: 4)
MessageCatcher
instances can be problematic when iterating over all objects to find pinned objects. That is because Object>>#isPinnedInMemory
no longer returns a boolean when used within a select block.
The code below adds isPinnedInMemory to MessageCatcher
MessageCatcher compile: (Object>>#isPinnedInMemory) sourceCode classified: (Object>>#isPinnedInMemory) category
It can also be useful to compute the memory size to understand the effects of pinned objects
SystemNavigation default allObjects sum: #sizeInMemory
Smalltalk vm statisticsReport