StandardSystemView subclass:#MemoryUsageView
instanceVariableNames:'info list sortBlock'
classVariableNames:''
poolDictionaries:''
category:'Interface-Debugger'
!
!MemoryUsageView methodsFor:'realization'!
realize
super realize.
self updateInfo.
self sortByClass.
! !
!MemoryUsageView methodsFor:'initialization'!
initialize
|l helpView headLine|
super initialize.
self label:'Memory usage'.
headLine := 'class # of insts avg sz bytes %mem'.
l := Label in:self.
l origin:(0.0 @ 0.0) corner:(1.0 @ l height).
l borderWidth:0.
l label:headLine.
l adjust:#left.
self extent:((font widthOf:headLine) + (device horizontalPixelPerMillimeter * 15) rounded) @ self height.
helpView := ScrollableView for:ListView in:self.
helpView origin:(0.0 @ l height)
extent:[width @ (height - l height - l margin)].
l origin:(helpView scrollBar width @ 0.0).
list := helpView scrolledView.
list origin:(0.0 @ 0.0) extent:(1.0 @ 1.0).
list middleButtonMenu:(PopUpMenu
labels:#(
'by class'
'by inst count'
'by memory usage'
'-'
'update'
)
selectors:#(sortByClass
sortByInstCount
sortByMemoryUsage
nil
update
)
receiver:self
for:list).
"MemoryUsageView start"
! !
!MemoryUsageView methodsFor:'menu actions'!
sortByClass
self label:'Memory usage; by class'.
sortBlock := [:a :b | (a at:1) name < (b at:1) name].
self updateDisplay
!
sortByInstCount
self label:'Memory usage; by instance count'.
sortBlock := [:a :b | (a at:2) > (b at:2) ].
self updateDisplay
!
sortByMemoryUsage
self label:'Memory usage; by memory usage'.
sortBlock := [:a :b | (a at:3) > (b at:3)].
self updateDisplay
!
update
self updateInfo.
self updateDisplay
! !
!MemoryUsageView methodsFor:'private'!
updateInfo
self cursor:Cursor wait.
list cursor:Cursor wait.
info := IdentityDictionary new:600.
"find all objects, collect stuff in info"
ObjectMemory allObjectsDo:[:o |
|i class|
o isBehavior ifTrue:[
o isMeta ifTrue:[
class := Metaclass
] ifFalse:[
class := Class
]
] ifFalse:[
class := o class.
].
(info includesKey:class) ifFalse:[
info at:class put:(Array with:class
with:1
with:(ObjectMemory sizeOf:o))
] ifTrue:[
i := info at:class.
i at:2 put:((i at:2) + 1).
i at:3 put:((i at:3) + (ObjectMemory sizeOf:o))
]
].
self cursor:Cursor normal.
list cursor:Cursor normal.
!
updateDisplay
|classNames counts sumSizes percents avgSizes rawData l line allMemory overAllCount overAllAvgSize|
self cursor:Cursor wait.
list cursor:Cursor wait.
rawData := info asSortedCollection:sortBlock.
"this avoids getting a sorted collection in the collect: below"
rawData := rawData asArray.
classNames := rawData collect:[:i |
|cls|
cls := i at:1.
cls == Class ifTrue:[
'<all classes>'
] ifFalse:[
cls == Metaclass ifTrue:[
'<all metaclasses>'
] ifFalse:[
cls name
]
]
].
counts := rawData collect:[:i | (i at:2) ].
sumSizes := rawData collect:[:i | (i at:3) ].
allMemory := ObjectMemory bytesUsed.
percents := sumSizes collect:[:sz | (sz / allMemory * 100 * 10) rounded / 10.0].
avgSizes := (1 to:sumSizes size) collect:[:i | (((sumSizes at:i) / (counts at:i)) * 10) rounded / 10.0].
l := OrderedCollection new.
1 to:classNames size do:[:i |
line := (classNames at:i) printStringPaddedTo:30 with:Character space.
line := line , ((counts at:i) printStringLeftPaddedTo:10).
line := line , ((avgSizes at:i) printStringLeftPaddedTo:10).
line := line , ((sumSizes at:i) printStringLeftPaddedTo:10).
line := line , ((percents at:i) printStringLeftPaddedTo:7).
l add:line
].
"add summary line"
overAllCount := counts inject:0 into:[:sum :this | sum + this].
overAllAvgSize := ((allMemory / overAllCount) * 10) rounded / 10.0.
l add:''.
line := 'all objects' printStringPaddedTo:30 with:Character space.
line := line , (overAllCount printStringLeftPaddedTo:10).
line := line , (overAllAvgSize printStringLeftPaddedTo:10).
line := line , (allMemory printStringLeftPaddedTo:10).
line := line , (100.0 printStringLeftPaddedTo:7).
l add:line.
list list:l.
self cursor:Cursor normal.
list cursor:Cursor normal.
! !