rails/rails — pull request #6687 by tiegz (2012-06-09 05:20:00+00:00)
Title: ActiveRecord#attributes optimization: minimize objects created

What
====

I propose reverting to the old implementation of `ActiveRecord#attributes` (changed in c4809d9984ab5d20759075a96ddea6096ab93802).

Why
====
The current way that `attributes` builds its attributes hash creates `(n * 2) + 1` extraneous arrays, where `n` is the number of attribute keys. Switching back to the old implementation reduces this to 0.

For instance, I have a model with 43 columns; with Memprof (on 1.8.7) we can see that `attributes` normally creates 87 Arrays because of the `map` usage:

```
1.8.7 :010 > Memprof.track { my_record.attributes }
87 /.../activerecord-3.2.5/lib/active_record/attribute_methods.rb:184:Array
1 /.../activerecord-3.2.5/lib/active_record/attribute_methods.rb:184:__node__
1 /.../activerecord-3.2.5/lib/active_record/attribute_methods.rb:184:Hash
```

Now when we switch back to the original implementation that builds a hash with `each` (despite having 2 more LOC), we can see the benefit:

```
1.8.7 :010 > Memprof.track { my_record.attributes }
1 /.../activerecord-3.2.5/lib/active_record/attribute_methods.rb:184:Hash
1 /.../activerecord-3.2.5/lib/active_record/attribute_methods.rb:179:Array
```

I didn't verify the object count in 1.9 myself, but I did a 1.9 GC profile and confirmed that GC did run fewer times overall with this change (over a large sample).

Note
====
afaik, `attributes` isn't actually used that often, however `serializable_hash` uses it. Since `serializable_hash` would most likely be used in apis where it's common to return lists of many records, it seems worthy of optimizing this method.