2022-03-13 Ruby でオブジェクトのメモリ量を計測するメソッド memsize_of_all_reachable_objects_from
昨日の記事では 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
下記の通り, 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#d8 の memsize_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
によって得ることが出来ます.