ObjectSpace.each_objectとはRuby投稿日:2020-02-09最終更新:2020-02-09クロス元の投稿をみる(https://shikiyura.sta...)こんにちは、しきゆらです。気が付くと、年が明けて2月です。今回は、先輩に教えてもらった謎のコードを解読していきます。謎のコードとは下記のもの。GC.startいきさつAWS上にあるインスタンスでRailsを動かしていました。その中で、DBのデータにミスがあったので、1.5万件ほどのデータに紐づく諸々の差し替え作業を行っていました。このときにおこった問題としては「メモリ使い過ぎで怒られる」という状況でした。コードを書き換えたりループを工夫したりしても解決せず困っていたとこで先輩が下記のようなコードを教えてくれました。end結果としては、処理中に止まることもなく走りきることができた。その当時は、すげぇなって思いつつこのコードを後で調べておこうと思ってメモしておいたが、放置されていたもの。時間ができたので、調べてみようと思って書いている。ObjectSpaceとはそもそも、見慣れないクラス名です。調べてみると、Rubyさんの組み込みモジュールでした。リファレンスマニュアル)とのこと。わかるようなわからないような・・・という感じですが、定義されているメソッド類を見てみるとRubyで定義したオブジェクトたちに対してあれこれしたり、プロファイルを取るときなどに使われるもののようでした。ObjectSpace#each_objectその中に、ありましたeach_objectメソッド。ObjectSpaceが何かわかれば、メソッド名で何をするものなのか大方予想が付きますね。リファレンスマニュアル)とのこと。上記のコードではActiveRecord::Relationクラスのオブジェクトすべてに対する処理を行うということですね。こいつは、ブロックを渡すとそのブロックを実行し、繰り返し回数を返すようです。ブロックが渡らない場合はEnumeratorオブジェクトを返すとのこと。上記のコードでは、eachメソッドをつなげているので後者ですね。引数を与えなければすべてのオブジェクトに対して繰り返すようです。値となるFixnumなどは対象外のようです。上記コードはActiveRecord::Relationクラスのすべてのオブジェクト一つ一つに対してresetメソッドを呼び出していることになりますね。ActiveRecord::Retation#resetでは、ActiveRecord::Retation#resetは何者でしょうか。定義を確認してみると、内部で保持しているデータをすべて破棄しているようです。上記コードの1行目が実行されたら、ActiveRecord::Retationのオブジェクトはすべて空のデータとなるようです。1行目の内容は把握できました。2行目を追っていきます。GC見たままGCでしょうね。一応調べてみると、RubyのGCを制御するためのモジュールでした。正確な情報は持っていませんが、イメージとしては使用していないデータを解放する仕組みという認識です。メモリ上にあるいらないものを削除してきれいにしてくれる裏方さん。GC#startもう、見たままでしょう。リファレンスマニュアル)GCの処理を始めるためのメソッドです。別メソッドでGCを禁止するようなこともできるようですが、このメソッドで実行した場合はGCを始めるようです。GC.startたった2行のコードですが、知らないことが満載でした。処理を簡単にまとめると、この処理の前までに作成されたすべてのActiveRecord::Relationオブジェクトを空にしてGCに削除してもらう感じでしょうか。1.5万件のデータを処理していると、たくさんの不要なオブジェクトがたまっていき途中で利用できるメモリサイズをオーバーしてしまうということで、それを防ぐために一定の処理を終えると不要になったオブジェクトを削除して次に進む、ということを行っているようですね。find_eachやfind_in_batchesなどである程度の粒度で処理することなどはわかっていましたが、それですら怒られるのでどうすればいいのかわからないところで、まさか自分でGCを動かして削除させることができるとは・・・。知らないことがいっぱいあるということですね。使うことではないとは思いますが、知っていると困ったときに役に立ちそうです。まとめ今回は、先輩が教えてくれた謎のコードを調べながら内容を理解してみました。ActiveRecordなど、Githubで公開されているコードについては中身を読むことができるので、きちんと中身を知っておくことは大事だなと思いました。