How to Measure the Size of a Ruby Object

How to measure the size of a Ruby object?

The excellent Eigenclass blog had an interesting article on that once:

http://web.archive.org/web/20120126022146/http://eigenclass.org/R2/writings/object-size-ruby-ocaml

There also was a good discussion on ruby-talk, which led to some code by Robert Klemme (Ruby Best Practices):

http://www.ruby-forum.com/topic/156648

http://www.pastie.org/217131

Plugging the values from the first article into the script might get you started and is probably quite educational.

You could also check out memprof, though it's more about object references and finding memory leaks than actual sizes:

http://github.com/ice799/memprof

Memory size of a hash or other object?

ObjectSpace.memsize_of does work in 1.9.3, documented or not:

puts RUBY_VERSION #=>1.9.3

require 'objspace'

p ObjectSpace.memsize_of("a"*23) #=> 23
p ObjectSpace.memsize_of("a"*24) #=> 24
p ObjectSpace.memsize_of("a".*1000) #=> 1000
h = {"a"=>1, "b"=>2}
p ObjectSpace.memsize_of(h) #=> 116

How do I get the size of a ruby object in mb in Rails?

The size of data rows in a database as well as the object size of ruby objects in memory are both not readily available unfortunately.

While it is a bit easier to get a feeling for the object size in memory, you would still have to find all objects which take part of your active record object and thus should be counted (which is not obvious). Even then, you would have to deal with non-obvious things like shared/cached data, class overhead, which might be required to count, but doesn't have to.

On the database side, it heavily depends on the storage engine used. From the documentation of your database, you can normally deduct the storage requirements for each of the columns you defined in your table (which might vary in case of VARCHAR, TEXT, or BLOB columns. On top of this come shared resources like indexes, general table overhead, ... To get an estimate, the documented size requirements for the various columns in your table should be sufficient though

Generally, it is really hard to get a correct size for complex things like database rows or in-memory objects. The systems are not build to collect or provide this information.

Unless you absolutely positively need to get an exact data, you should err on the side of too much space. Generally, for databases it doesn't hurt to have too much disk space (in which case, the database will generally run a little faster) or too much memory (which will reduce memory pressure for Ruby which will again make it faster).

Often, the memory usage of Ruby processes will be not obvious. Thus, the best course of action is almost always to write your program and then test it with the desired amount of real data and check its performance and memory requirements. That way, you get the actual information you need, namely: how much memory does my program need when handling my required dataset.

How to measure ActiveRecord's size on memory?

The size method returns the number of bytes in the machine representation of the number. It doesn't necessarily (and doesn't in practice) give you the the actual memory usage. While a Fixnum does indeed take 4 Bytes of memory (in MRI, other Ruby implementations differ), a Bignum takes more memory as it it an actual Ruby object.

Similarly, other classes which implement a size method like String, Array, or Hash doesn't return memory usage but the number of elements they contain (characters, array elements, keys respectively).

Generally, you can't really determine how much memory an object takes in memory (well, you can, but it would not give you the information you want). An ActiveRecord object refers to a large number of other objects like Hashes, Strings, Symbols, .... You would probably need to count them too, probably even recursive. Then you somehow need to deal with references to the same objects, and somewhere define the boundary of your object tree until you end up re-implementing most of the garbage collector.

So in the end, it turns out, you can't practically determine the memory usage of a single ActiveRecord object and you probably shouldn't. For more details, please also refer to a similar answer of mine on another question.

Size of class in bytes

There is no language feature that calculates the size of a class in the same way as C.

The memory size of an object is implementation dependent. It depends on the implementation of the base class object. It is also not simple to estimate the memory used. For example, strings can be embedded in an RString structure if they are short, but stored in the heap if they are long (Never create Ruby strings longer than 23 characters).

The memory taken by some objects has been tabulated for different ruby implementations: Memory footprint of objects in Ruby 1.8, EE, 1.9, and OCaml

Finally, the object size may differ even with two objects from the same class, since it is possible to arbitrarily add extra instance variables, without hardcoding what instance variables are present. For example, see instance_variable_get and instance_variable_set


If you use MRI ruby 1.9.2+, there is a method you can try (be warned that it is looking at only part of the object, this is obvious from the fact that integers and strings appear to have zero size):

irb(main):176:0> require 'objspace'
=> true
irb(main):176:0> ObjectSpace.memsize_of(134)
=> 0
irb(main):177:0> ObjectSpace.memsize_of("asdf")
=> 0
irb(main):178:0> ObjectSpace.memsize_of({a: 4})
=> 184
irb(main):179:0> ObjectSpace.memsize_of({a: 4, b: 5})
=> 232
irb(main):180:0> ObjectSpace.memsize_of(/a/.match("a"))
=> 80

You can also try memsize_of_all (note that it looks at the memory usage of the whole interpreter, and overwriting a variable does not appear to delete the old copy immediately):

irb(main):190:0> ObjectSpace.memsize_of_all
=> 4190347
irb(main):191:0> asdf = 4
=> 4
irb(main):192:0> ObjectSpace.memsize_of_all
=> 4201350
irb(main):193:0> asdf = 4
=> 4
irb(main):194:0> ObjectSpace.memsize_of_all
=> 4212353
irb(main):195:0> asdf = 4.5
=> 4.5
irb(main):196:0> ObjectSpace.memsize_of_all
=> 4223596
irb(main):197:0> asdf = "a"
=> "a"
irb(main):198:0> ObjectSpace.memsize_of_all
=> 4234879

You should be very careful because there is no guarantee when the Ruby interpreter will perform garbage collection. While you might use this for testing and experimentation, it is recommended that this is NOT used in production!

Does the size of the objects in a Ruby array contribute to the memory usage of the array itself?

In MRI Ruby, an array does not copy and contain the values of all the objects inside it. The array contains a series of pointers in memory. So the size of an array is the size of the struct necessary for the array's internal pieces (e.g. capacity, length), plus the size of one pointer (a void*, so 4 bytes on a 32-bit architecture) per object in the array. The objects in the array occupy their own memory space elsewhere.

Ruby get the size in bytes of an array

Like WTP said, you probably intend on returning the size of the JSON representation instead of ruby representation of the array, because the JSON is the actual response to the browser. You can do this by encoding beforehand (yielding a string) and then checking its size.

response['Content-Length'] = ActiveSupport::JSON.encode(items).size

More about JSON serialization and rails

How can I find the size of an uploaded file in Ruby on Rails?


File.size(doc.filename)

Just throw the name of the file into the curly brackets and you should be set.

If you want KB/MB use:

number_to_human_size(File.size(doc.filename))

EDIT:

You can use the exact path or Pathname

1.9.3p125 :005 > x=Pathname.new("/usr/bin/ruby")
=> #<Pathname:/usr/bin/ruby>
1.9.3p125 :006 > File.size(x)
=> 5488

For extension:

File.extname("test.rb")         #=> ".rb"

How do I calculate a String's width in Ruby?

You should use the RMagick gem to render a "Draw" object using the font you want (you can load .ttf files and such)

The code would look something like this:

   the_text = "TheTextYouWantTheWidthOf"
label = Draw.new
label.font = "Vera" #you can also specify a file name... check the rmagick docs to be sure
label.text_antialias(true)
label.font_style=Magick::NormalStyle
label.font_weight=Magick::BoldWeight
label.gravity=Magick::CenterGravity
label.text(0,0,the_text)
metrics = label.get_type_metrics(the_text)
width = metrics.width
height = metrics.height

You can see it in action in my button maker here: http://risingcode.com/button/everybodywangchungtonite



Related Topics



Leave a reply



Submit