Hi Niko,
the header size calculation is also wrong. If the byte size if the object body is > 255 bytes there needs to be an additional header size word. So something like
byteSizeOfBody := anObject class isBytes ifTrue: [....] ifFalse: [.....]. headerSize := byteSizeOfBody > 255 ifTrue: [12] ifFalse: [anObject class indexIfCompact > 0 ifTrue: [4] ifFalse: [8]].
On Wed, Mar 14, 2012 at 1:05 PM, niko.schwarz@googlemail.com wrote:
Hi guys,
I haven't checked if this bug exists already, so please ignore this if it's been reported before.
Bug in WAMemoryItem:
sizeOfObject: anObject | headerSize instanceSize variableSize | headerSize := anObject class indexIfCompact > 0 ifTrue: [ 4 ] ifFalse: [ 8 ]. instanceSize := anObject class instSize. variableSize := anObject class isBytes ifTrue: [ anObject basicSize ] ifFalse: [ anObject class isWords ifTrue: [ Smalltalk wordSize * anObject basicSize ] ifFalse: [ Smalltalk wordSize * anObject basicSize // 2 ] ]. ^ headerSize + instanceSize + variableSize
In this snippet, the units that are added together in the last line are of different units.
instanceSize is in unit "number of machine words", whereas variableSize and headerSize are in unit "bytes".
The method is fixed here:
sizeOfObject: anObject | headerSize instanceSize variableSize | headerSize := anObject class indexIfCompact > 0 ifTrue: [ 4 ] ifFalse: [ 8 ]. instanceSize := anObject class instSize * Smalltalk wordSize. variableSize := anObject class isBytes ifTrue: [ anObject basicSize ] ifFalse: [ anObject class isWords ifTrue: [ Smalltalk wordSize * anObject basicSize ] ifFalse: [ Smalltalk wordSize * anObject basicSize // 2 ] ]. ^ headerSize + instanceSize + variableSize
Example:
|m| dict := Dictionary new. m := WAMemory new. dict traverseWithMemory: m seen: IdentitySet new. m totalSize
This will incorrectly spit out 10, but should return 16, on a 32 bit VM.
Niko
-- http://scg.unibe.ch/staff/Schwarz twitter.com/nes1983 Tel: +41786126354
And there is also #sizeInMemory
sizeInMemory "Answer the number of bytes consumed by this instance including object header." | contentBytes |
contentBytes := Smalltalk wordSize. "base header" contentBytes := contentBytes + (self class instSize * Smalltalk wordSize). "instance vars"
self class isVariable ifTrue:[ | bytesPerElement | "indexed elements" bytesPerElement := self class isBytes ifTrue: [1] ifFalse: [4]. contentBytes := contentBytes + (self basicSize * bytesPerElement) ].
contentBytes > 255 ifTrue: [ contentBytes := contentBytes + (2 * Smalltalk wordSize) ] ifFalse: [ self class isCompact ifFalse: [ contentBytes := contentBytes + Smalltalk wordSize] ]. ^contentBytes
which is also wrong for the cases of String. For example, 'aa' sizeInMemory answers 6 but should be 8 because of alligment. If someone fixes this, I think #sizeInMemory would be correct.
Cheers
On Thu, Mar 15, 2012 at 6:53 PM, Eliot Miranda eliot.miranda@gmail.comwrote:
Hi Niko,
the header size calculation is also wrong. If the byte size if the
object body is > 255 bytes there needs to be an additional header size word. So something like
byteSizeOfBody := anObject class isBytes ifTrue: [....] ifFalse: [.....]. headerSize := byteSizeOfBody > 255 ifTrue: [12] ifFalse: [anObject class indexIfCompact > 0 ifTrue: [4] ifFalse: [8]].
On Wed, Mar 14, 2012 at 1:05 PM, niko.schwarz@googlemail.com wrote:
Hi guys,
I haven't checked if this bug exists already, so please ignore this if it's been reported before.
Bug in WAMemoryItem:
sizeOfObject: anObject | headerSize instanceSize variableSize | headerSize := anObject class indexIfCompact > 0 ifTrue: [ 4 ] ifFalse: [ 8 ]. instanceSize := anObject class instSize. variableSize := anObject class isBytes ifTrue: [ anObject basicSize ] ifFalse: [ anObject class isWords ifTrue: [ Smalltalk wordSize * anObject basicSize ] ifFalse: [ Smalltalk wordSize * anObject basicSize // 2 ] ]. ^ headerSize + instanceSize + variableSize
In this snippet, the units that are added together in the last line are of different units.
instanceSize is in unit "number of machine words", whereas variableSize and headerSize are in unit "bytes".
The method is fixed here:
sizeOfObject: anObject | headerSize instanceSize variableSize | headerSize := anObject class indexIfCompact > 0 ifTrue: [ 4 ] ifFalse: [ 8 ]. instanceSize := anObject class instSize * Smalltalk wordSize. variableSize := anObject class isBytes ifTrue: [ anObject basicSize ] ifFalse: [ anObject class isWords ifTrue: [ Smalltalk wordSize * anObject basicSize ] ifFalse: [ Smalltalk wordSize * anObject basicSize // 2 ] ]. ^ headerSize + instanceSize + variableSize
Example:
|m| dict := Dictionary new. m := WAMemory new. dict traverseWithMemory: m seen: IdentitySet new. m totalSize
This will incorrectly spit out 10, but should return 16, on a 32 bit VM.
Niko
-- http://scg.unibe.ch/staff/Schwarz twitter.com/nes1983 Tel: +41786126354
-- best, Eliot
vm-dev@lists.squeakfoundation.org