0Pricing
Ruby Academy · レッスン

メモリ最適化

割り当てを減らします。

「メモリ最適化」はCoddyKit上の無料Ruby Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはRuby Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Ruby Academyコースには全4レッスンが含まれています。

メモリが重要な理由

Rubyが生成するすべてのオブジェクトはメモリを消費し、ガベージコレクションの処理を増やします。割り当てを減らすと、プログラムを高速かつ軽量にできます。

  • GCはオブジェクトを回収するために一時停止します
  • 割り当て頻度が高いと、GCの実行回数が増えます
  • 割り当てを減らすことが、最も大きな改善につながる場合がよくあります
before = GC.stat(:total_allocated_objects)
100.times { 'new string' + '!' }
after = GC.stat(:total_allocated_objects)
puts "Allocated: #{after - before} objects"

割り当て数を数える

GC.statを使うと、ブロックの前後で割り当てカウンターを比較できます。

  • :total_allocated_objectsは増え続けます
  • 前後の差分を取って、対象部分を計測します
def allocations
  before = GC.stat(:total_allocated_objects)
  yield
  GC.stat(:total_allocated_objects) - before
end

puts allocations { Array.new(1000) { |i| i.to_s } }

文字列リテラルの凍結

同じ文字列リテラルを繰り返し使うと、そのたびに新しいオブジェクトが割り当てられます。文字列を凍結すると、Rubyは変更できない1つのインスタンスを再利用できます。

  • ファイルの先頭にマジックコメントを追加します
  • または、個々のリテラルに.freezeを呼び出します
# frozen_string_literal: true

s1 = 'hello'
s2 = 'hello'
puts s1.equal?(s2)

ループ内の割り当てを避ける

負荷の高いループ内でオブジェクトを作成すると、割り当てが何度も発生します。定数をループの外に移動します。

  • 正規表現、配列、文字列を一度だけ作成します
  • 繰り返し処理の間で再利用します
PATTERN = /\d+/

def count_numbers(lines)
  lines.count { |line| line.match?(PATTERN) }
end

puts count_numbers(['a1', 'bb', 'c3'])

破壊的メソッド(bang)

bangメソッドではないメソッドは新しいオブジェクトを返します。一方、bangメソッドは元のオブジェクトをその場で変更するため、割り当てを抑えられます。

  • map!、gsub!、sort!
  • 元のオブジェクトを変更しても安全な場合にだけ使用します
arr = [3, 1, 2]
arr.sort!
puts arr.inspect

s = 'hello world'
s.upcase!
puts s

キーとしてのシンボルと文字列

シンボルはインターンされるため、同じシンボルは共有される1つのオブジェクトになります。ハッシュのキーにはシンボルを使用します。

  • 文字列をキーにすると、使うたびに新しい文字列が割り当てられます
  • 繰り返し検索する場合、シンボルによってメモリを節約できます
puts :name.equal?(:name)
puts 'name'.equal?('name')

遅延列挙子

mapとselectをチェーンすると、中間配列が作成されます。lazyを使うと、要素を1つずつ処理できます。

  • 中間コレクションが割り当てられません
  • 大規模なシーケンスや無限シーケンスに適しています
result = (1..Float::INFINITY).lazy
  .select { |n| n.even? }
  .map { |n| n * n }
  .first(5)
puts result.inspect

読み込まずにストリーミング

ファイル全体をメモリに読み込むのは非効率的です。1行ずつストリーミングします。

  • each_lineは1行ずつ処理します
  • ファイルのサイズに関係なく、使用するメモリは一定です
text = "line1\nline2\nline3"
text.each_line do |line|
  puts line.strip.upcase
end

文字列の連結

ループ内で+を使って文字列を構築すると、毎回新しい文字列が割り当てられます。<<を使って、その場で追加します。

  • +は新しいオブジェクトを作成します
  • <<は既存のバッファを変更します
buffer = String.new
5.times { |i| buffer << "item#{i} " }
puts buffer

オブジェクトのプールと再利用

高コストなオブジェクトは作り直さずに再利用します。

  • 解析済みの設定やコンパイル済みの正規表現をキャッシュします
  • 定数またはメモ化した値を使用します
def config
  @config ||= { host: 'localhost', port: 4567 }
end

puts config.equal?(config)

GCを実行して効果を確認

GCの動作を調べて、改善を確認できます。

  • GC.stat(:count)は、GCが実行された回数を示します
  • 最適化後に実行回数が減っていれば、よい兆候です
start = GC.stat(:count)
50_000.times { |i| [i] }
puts "GC runs: #{GC.stat(:count) - start}"

クイックチェック

メモリ最適化についての知識を確認しましょう。

振り返り

メモリを最適化する方法を学びました。

  • GC.statで割り当て数を数えます
  • 文字列リテラルを凍結し、オブジェクトを再利用します
  • 新しいオブジェクトの作成を避けるため、bangメソッドと<<を優先します
  • キーにはシンボルを、パイプラインには遅延列挙子を使用します
  • 大きなデータはすべて読み込まず、ストリーミングします

次は、よくあるパフォーマンスのボトルネックに取り組みます。

よくある質問

「メモリ最適化」レッスンは無料ですか?

はい。「メモリ最適化」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Ruby Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Ruby Academyコースには全4レッスンが含まれています。

「メモリ最適化」で何を学びますか?

割り当てを減らします。 ブラウザで直接実行するハンズオンコードでRuby Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Ruby Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのRuby Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「メモリ最適化」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このRuby Academyレッスンでコードを書いて実行できますか?

はい。すべてのRuby Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. パフォーマンスの測定
  2. プロファイリングツール
  3. メモリ最適化
  4. よくあるボトルネック
← Ruby Academyに戻る