昨日の記事では ruby の memsize_of, memsize_of_all を紹介した。

2022-03-12 ObjectSpace.#memsize_of / ObjectSpace.#memsize_of_all

しかしこのメソッドは下記の点に注意する必要がある。

puts ObjectSpace.memsize_of(Hoge.new)

ただし、対象のオブジェクトが他のオブジェクトを保有している場合は、ポインタのメモリ量しか計測しないため、「対象のオブジェクトに関連する全てのオブジェクトのメモリ量ではない」ということに注意する必要があります。

関連する全てのオブジェクトのメモリ量を取得するには、reachable_objects_fromメソッドを使って関連するオブジェクトをたどる必要があります。詳細は以下のリンクを参照してください。 http://www.atdot.net/~ko1/diary/201212.html#d8

Rubyプロセスの使用メモリ量の計測

下記の通り, Array の中身までは計算してくれないことがわかる。

ObjectSpace.memsize_of("a") #=> 40
ObjectSpace.memsize_of("a" * 100) #=> 141

ObjectSpace.memsize_of(["a"]) #=> 40
ObjectSpace.memsize_of(["a" * 100]) #=> 40

memsize_of_all_reachable_objects_from

https://www.atdot.net/~ko1/diary/201212.html#d8memsize_of_all_reachable_objects_from メソッドをベースに一部改変。

require 'objspace'

def memsize_of_all_reachable_objects_from(obj, exclude_class = Module)
  objs = {}
  queue = [obj]
  key = ->(o) { o.is_a?(ObjectSpace::InternalObjectWrapper) ? o.internal_object_id : o.object_id }

  while obj = queue.pop
    next if objs[obj.object_id]

    ObjectSpace.reachable_objects_from(obj).each do |reachable_object|
      next if objs[key.call(reachable_object)]
      queue << reachable_object unless reachable_object.is_a?(exclude_class)
    end

    objs[key.call(obj)] = obj
  end
  objs.values.sum { |obj| ObjectSpace.memsize_of(obj) }
end

このメソッドを使ってArrayを再度計測してみる。

memsize_of_all_reachable_objects_from("a") #=> 40
memsize_of_all_reachable_objects_from("a" * 100) #=> 141

memsize_of_all_reachable_objects_from(["a"]) #=> 80
memsize_of_all_reachable_objects_from(["a" * 100]) #=> 181

きちんと中身も含めて出力されました。めでたしめでたし。

What is InternalObjectWrapper?

さて,InternalObjectWrapper#object_id は,もちろんこの wrapper オブジェクトの object_id を取り出しますが,wrap したオブジェクトの object_id が取り出したいことがあります.それを,InternalObjectWrapper#internal_object_id によって得ることが出来ます.

http://www.atdot.net/~ko1/diary/201212.html#d9