内存优化
减少分配
内存优化 是 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 反馈 — 无需本地设置。