Memory overhead for small objects: often underestimated
Added information about the cost of a Symbol
(also heavier than you might have expected), and the RStruct optimization in
1.9.
It is well known that the minimal space overhead for a non-immediate object in Ruby is 20 bytes*1. But the overhead will be much higher if your object happens to have instance variables (read: almost always).
Take for instance
class Stupid; attr_accessor :foo end class Stupid2; attr_accessor :foo, :bar end o1 = Stupid.new o1.foo = 1 o2 = Stupid2.new o2.foo = 1 o2.bar = 2
o1 will take around
and o2
bytes, i.e. for objects with under 55 instance
variables, the memory footprint is around 100 bytes plus 20 bytes per
instance variable --- that's quite heavy.
The exact numbers depend on the behavior of malloc regarding memory alignment and overhead. Doug Lea's malloc, in wide use, takes 8 or 4 bytes per chunk.
Here are some other overheads for Arrays, Hashes, Symbols, etc. (+M denotes the malloc overhead per allocated chunk, normally 4 or 8 bytes):
- basic RVALUE overhead: 20 bytes
- Array: add 16 * 4 (+M) [ptr] (up to 16 elements)
- object with instance variables: add 16(+M) [st_table] + 11 * 4 (+M) [bins] + 4 * 4 (+M) [st_table_entry] (bins: constant up to 55 instance variables; add 4 * 4 (+M) per element)
- Hash: add 16(+M) + 11 * 4 (+M) + 4 * 4 (similar to the iv_tbl overhead)
- Struct: add 4 (+M) per "attribute"
a Symbol takes sym.to_s.size + 1 (typically padded to 8 bytes, with a minimum of 16 bytes) plus 2 * (16 (+M)) (minimum), e.g. after you do "foo".to_sym, ~56 bytes are allocated, never to be released
In Ruby 1.9, up to 3 attributes can be packed in the internal RStruct
structure, which means that in
Foo = Struct.new(:a, :b, :c) a = Foo.new(1,2,3)
the object referenced by a takes only 20 bytes, instead of 44/68 bytes as in previous versions. Compare that cost (20 bytes in 1.9, ~50 in 1.8) to that of a normal object with 3 instance variables: around 160 bytes, that is 3 to 8 times heavier!
n - s (2006-07-17 (Mon) 19:19:27)
s
*1 all the values given here correspond to a 32bit platform
Keyword(s):[blog] [ruby] [memory] [overhead]
References:[Symbols, meta-programming and leaks. On harakiri and DoSing Rails?] [When the GC is doing its job, but your app still needs too much RAM]