46

What's the best way to get the size of a given hash (or any object really) in bytes in Ruby 1.9.3?

The solution to "Find number of bytes a particular Hash is using in Ruby" does not appear to be valid in 1.9.3, because memsize_of isn't in the documentation for ObjectSpace.

Community
  • 1
  • 1
bevanb
  • 8,201
  • 10
  • 53
  • 90
  • 1
    Do you want to know the size of it recursively, or just the Hash itself? I mean, if you already have objects stored in other variables, but also in the Hash, do you want to consider them as contributing to the Hash size? (Having one object in more than one place doesn't use twice the memory). /Just thinking about how to do this in the underlying C API. – d11wtq Apr 09 '12 at 01:53
  • 1
    Good question. I'm just interested in the hash itself, and the string values contained therein. – bevanb Apr 09 '12 at 02:09
  • Question seems similar to this: http://stackoverflow.com/questions/3973094/how-to-measure-the-size-of-a-ruby-object – joshnuss Apr 02 '13 at 06:04
  • 10
    You are not supposed to offer monetary compensation for answers on Stack Overflow. There is a whole system of incentives in place and money is not a part of it. – Cezar Apr 04 '13 at 12:19

3 Answers3

62

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
Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
steenslag
  • 79,051
  • 16
  • 138
  • 171
  • 3
    Unfortunately, for 2.1.4 it does't. `ObjectSpace.memsize_of("a"*23)` returns `0` – installero Aug 11 '15 at 10:23
  • 2
    This is because now it represent the memory outside of the ruby heap – ciaoben Sep 16 '15 at 09:52
  • 19
    What exactly does this method return, the size in bytes of the object in memory? – ErikAGriffin Oct 25 '15 at 11:59
  • 12
    Even the doc page for `ObjectSpace#memsize_of` doesn't list what the units are. Incredibly annoying to have to hunt for something basic. – user2490003 Sep 22 '16 at 22:13
  • @JaredMenard, I believe they are bits – Gabriel Jun 19 '19 at 18:17
  • 5
    **ObjectSpace.memsize_of returns bytes**. I've compared results with `NewRelic::Agent::Samplers::MemorySampler.new.sampler.get_sample` which gives its result in MB ([proof](https://github.com/newrelic/rpm/blob/2bc79e102185861ff078fd15ccbf31a32f088b8a/lib/new_relic/agent/samplers/memory_sampler.rb#L111)) and obtained that the ratio between both is `1024*1024`. Hence it's bytes. – Ulysse BN Feb 04 '20 at 19:07
  • 1
    In ruby 2.6.4 `ObjectSpace.memsize_of("a"*23)` returns 40. Not sure why. Any ideas? – Shankar Thyagarajan Aug 20 '20 at 14:09
  • If you're using on an ActiveRecord object, convert it to json first. E.g.: `ObjectSpace.memsize_of(User.all.to_json)` – stevec Feb 27 '23 at 00:32
11

I once had the same problem. You have to be aware, that the real size is almost impossible to determine, since it depends on which VM you are using, which version of the VM and so on. Also, if you are referencing a string, that is also referenced somewhere else, then unsetting your hash doesn't mean that the specific contained string will also be unset, since it is already referenced somewhere else.

I once wrote an analyzer to count the estimated size of objects, by going through all contained objects in the given object. Get inspired to write your own:

https://github.com/kaspernj/knjrbfw/blob/master/lib/knj/memory_analyzer.rb#L334

Mine works like this:

require "rubygems"
require "knjrbfw"

analyzer = Knj::Memory_analyzer::Object_size_counter.new(my_hash_object)

puts "Size: #{analyzer.calculate_size}"
kaspernj
  • 1,243
  • 11
  • 16
  • 4
    this code exist error! it should be like this: `analyzer = Knj::Memory_analyzer::Object_size_counter.new(my_hash_object)` – comme May 23 '13 at 02:39
-3

An alternative way of having a rough estimate of the size of a hash is to convert it into a string and count the number of characters, each character will be a byte.

hash = {hello:  "world"}
=> {:hello=>"world"}
hash.to_s
=> "{:hello=>\"world\"}"
hash.to_s.size
=> 17

Then you can use a characters to bytes/megabytes calculator

jfanals
  • 1,006
  • 1
  • 13
  • 28
  • This post is misleading, the above mentioned hash takes 232 bytes instead of 17: `require('objspace');ObjectSpace.memsize_of({hello: "world"}) => 232` – David May 01 '20 at 14:11
  • For more complicated nested hashes makes sense to convert to string `to_s` to calculate the size, if you try `ObjectSpace.memsize_of(deep_hash)` you won't get a wrong size. – Boris Barroso Mar 24 '21 at 13:49
  • @David why is the difference so large. I would have though `.to_s.size` would give a good estimate. – stevec Feb 26 '23 at 01:12