Tenderlove Making

Counting Write Barrier Unprotected Objects

This is just a quick post mostly as a note to myself (because I forget the jq commands). Ruby objects that are not protected with a write barrier must be examined on every minor GC. That means that any objects in your system that live for a long time and don’t have write barrier protection will cause unnecessary overhead on every minor collection.

Heap dumps will tell you which objects have a write barrier. In Rails apps I use a small script to get a dump of the heap after boot:

require 'objspace'
require 'config/environment'

GC.start

File.open("heap.dump", "wb") do |f|
  ObjectSpace.dump_all(output: f)
end

The heap.dump file will have a list of all of the objects in the heap.

Here is an example of an object with a write barrier:

{"address":"0x7fec1b2ff940", "type":"IMEMO", "class":"0x7fec1b2ffd50", "imemo_type":"ment", "references":["0x7fec1b314908", "0x7fec1b2ffcd8"], "memsize":48, "flags":{"wb_protected":true, "old":true, "uncollectible":true, "marked":true}}

Here is an example of an object without a write barrier:

{"address":"0x7fec1b2ff760", "type":"ICLASS", "class":"0x7fec1a8c0f60", "references":["0x7fec1a8c9250", "0x7fec1b2fefe0"], "memsize":40}

Objects with a write barrier will have "wb_protected":true in their flags section.

I like to use jq to process heap dumps. Here is a command to find all of the unprotected objects, group them by type, then count them up:

$ jq 'select(.flags.wb_protected | not) | .type' heap.dump  | sort | uniq -c | sort -n
   1 "MATCH"
   2 "ARRAY"
   5 "ROOT"
   9 "FILE"
 323 "MODULE"
 927 "ICLASS"
1631 "DATA"

All of the objects listed here will be examined on every minor GC. If my Rails app is spending a lot of time in minor GCs, this is a good place to look.

Ruby 2.8 (or 3.0) will eliminate ICLASS from this list (here is the commit).

« go back