0Pricing
Ruby Academy · 课时

内存优化

减少分配

内存优化 是 CoddyKit 上的免费 Ruby Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Ruby Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Ruby Academy 课程共包含 4 节课。

内存为何重要

Ruby 创建的每个对象都会占用内存,并增加垃圾回收工作量。更少的 allocations 意味着更快、更精简的程序。

  • 垃圾回收器会暂停以回收对象
  • 较高的分配速率会触发更多次垃圾回收
  • 减少 allocations 往往是收益最大的优化
before = GC.stat(:total_allocated_objects)
100.times { 'new string' + '!' }
after = GC.stat(:total_allocated_objects)
puts "Allocated: #{after - before} objects"

统计 allocations

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 就可以复用同一个不可变实例。

  • 在文件顶部添加魔法注释
  • 或者对单个字面量调用 .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'])

修改方法(感叹号方法)

非感叹号方法会返回新对象;感叹号方法会原地修改对象,从而节省分配。

  • map!、gsub!、sort!
  • 只有在修改原对象是安全的情况下才使用它们
arr = [3, 1, 2]
arr.sort!
puts arr.inspect

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

用符号还是字符串作为键

符号会被驻留:相同的符号是同一个共享对象。请将它们用于哈希键。

  • 字符串键每次都会分配一个新字符串
  • 在重复查找时,符号可以节省内存
puts :name.equal?(:name)
puts 'name'.equal?('name')

惰性枚举器

链式调用 map 和 select 会构建中间数组。lazy 会一次处理一个元素。

  • 不会分配中间集合
  • 非常适合大型或无限序列
result = (1..Float::INFINITY).lazy
  .select { |n| n.even? }
  .map { |n| n * n }
  .first(5)
puts result.inspect

流式处理而不是全部加载

将整个文件读入内存十分浪费。请改为逐行流式处理。

  • each_line 一次处理一行
  • 无论文件大小如何,内存占用都保持恒定
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.stat(:count) 会显示垃圾回收运行了多少次
  • 优化后运行次数减少是一个好迹象
start = GC.stat(:count)
50_000.times { |i| [i] }
puts "GC runs: #{GC.stat(:count) - start}"

快速检查

测试您对内存优化的理解。

回顾

您学会了优化内存:

  • 使用 GC.stat 统计对象分配
  • 冻结字符串字面量并复用对象
  • 优先使用感叹号方法和 <<,避免创建新对象
  • 使用符号作为键,使用惰性枚举器处理管道
  • 对大型数据进行流式处理,而不是全部加载

接下来,您将学习常见的性能瓶颈。

常见问题解答

「内存优化」课时是免费的吗?

是的 — 「内存优化」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Ruby Academy 课程的其余内容,请升级到 CoddyKit PRO。 Ruby Academy 课程共包含 4 节课。

「内存优化」这节课中我会学到什么?

减少分配 你通过在浏览器中直接运行的动手代码来练习 Ruby Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Ruby Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Ruby Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「内存优化」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Ruby Academy 课中编写并运行代码吗?

能。每节 Ruby Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 测量性能
  2. 性能分析工具
  3. 内存优化
  4. 常见瓶颈
← 返回 Ruby Academy