Ah, I didn’t realize the headers were that much larger on the 64-bit JVM, nor did I realize that even small arrays had a size slot.
In theory we could introduce SingletonTupleDescriptor that didn’t bother with a hash slot. When there are no integer slots, a dedicated empty array stored in a static is used for the integer slots. Likewise for the object slots. So in that case we would have 96 - 24 = 72 bytes for the tuple. The hash value could just be calculated on demand. It would only be a significant slowdown when hashing constructs like <<<<<<<<<<foo>>>>>>>>>>. There are also all sorts of other tricks we could do, like introducing a dedicated field in the descriptor itself. We do that for POJOs (plain old Java objects) in Avail. That requires a separate instance of the descriptor for each POJO, however, and that would probably be significantly more expensive than the existing tuple implementation. Oh, and if we do a hash-less SingletonTupleDescriptor in the 64-bit LLVM version we should be able to shave it down to just the object pointer and header, for 16 bytes (8 bytes for 32-bit). Going below that would get /very/ tricky. > On Jan 5, 2015, at 4:30 PM, Robbert van Dalen <[email protected]> > wrote: > > hi, > > regarding the memory consumption of a tuple containing 1 object reference, i > believe the following to be (more) accurate: > > 1. the tuple Avail object: > -1 object header @ 8 bytes (klass pointer + monitor + gc bits). > - 3 slots in the AvailObject itself (descriptor ref, objectSlots ref, > intSlots ref) @ 4 bytes > * total of 24 bytes (padded) > > but… we also need to take the descriptor object, integer array and object > array into account: > > 2. the descriptor object: > … are shared and globally allocated once - so not taken into account. > > 3. the integer array object containing 1 int (the hash) > - 1 object header @ 8 bytes > - 1 size slot @ 4 bytes > - 1 int @ 4 bytes > * total of 16 bytes * > > 4. the object array object containing 1 object reference > - 1 object header @ 8 bytes > - 1 size slot @ 4 bytes > - 1 object reference @ 4 bytes > * total of 16 bytes * > > a total of 56 bytes on a 32 bits jvm. > > on a 64 bit jvm, that figure is going to be obviously worse: uncompressed, > every object header goes from 8 to 16 bytes and every object reference goes > from 4 to 8 bytes: > > 1. tuple object (64 bit, uncompressed): 40 bytes > 2. integer array (64 bit, uncompressed): 24 bytes > 3. object array (64 bit, uncompressed): 32 bytes (padded). > > a total of 96 bytes o a 64 bit jvm - uncompressed. > > compressed, every object header goes from 8 to 12 bytes and every object > reference will stay 4 bytes (if the heap stay below 4 gig). > > 1. tuple object (64 bit, compressed): 24 bytes > 2. integer array (64 bit, compressed): 24 bytes (padded). > 3. object array (64 bit, compressed): 24 bytes (padded). > > a total of 72 bytes on a 64 bit jvm - compressed. > that’s 3 times as big as a regular java object array containing one object > reference. > > i’m sure the llvm memory representation will be much better. > > cheers, > - robbert > >> Like all AvailObjects, a tuple has the usual Java header and two slots, one >> for the array of AvailObjects and one for the array of ints. An ordinary >> tuple (not one containing, say, a character or a nybble) has one object slot >> and one integer slot, so both arrays are necessary. When there are zero >> object slots or integer slots in an AvailObject, the single shared empty >> array of objects or the single shared empty array of ints is used instead of >> creating one especially for that AvailObject. However, since we need one >> slot of each for the one-element ordinary tuple (whose descriptor is an >> ObjectTupleDescriptor), we have: >> >> 3 object headers (AvailObject, AvailObject [], int []) @ 8 bytes each, >> 3 slots in the AvailObject itself (descriptor, objectSlots, intSlots) @ >> 8 bytes each >> 1 slot in the int [] @ 4 bytes (to cache the tuple's hash value) >> 1 slot in the AvailObject [] @ 8 bytes (the tuple element) >> >> So a one-element tuple takes 60 bytes. On the other hand, the zero element >> tuple is shared and takes no additional space per use (the slot holding it >> would be accounted with whatever structure owns the slot). >> >> Compressed pointers would shave it to 44 bytes. The custom representation >> we'll be using with LLVM will look like: >> >> ...before the object... >> [tuple element #1] @ 8 bytes >> [middle-header] @ 8 bytes >> [int slot #1 for hash] @ 4 bytes >> ...after the object... >> >> = 20 bytes. >
signature.asc
Description: Message signed with OpenPGP using GPGMail
