Currently, for any bulk access on primitive arrays (e.g. *_at_addr() family of methods, arraycopy, and the like), we do Access::resolve() on the base arrayOop (via arrayOopDesc::base() ). This is safe and does the right thing, but it is overly broad. In a garbage collector like Shenandoah, Access::resolve() would have to do a write-barrier, which is a copy-on-write. This could lead to double-copying of potentially large arrays, i.e. resolving the src array would copy it from from-space to to-space, and then it needs to be copied again from src to dst. Most of the accesses via _at_addr() are read-accesses, and they could use a weaker read-barrier, which only chases the forwarding pointer.