分享 Ruby 和它的内存之三点

dandananddada · 2015年05月16日 · 最后由 dandananddada 回复于 2015年05月17日 · 1782 次阅读

引自

http://www.sitepoint.com/ruby-uses-memory/ 只截取了前面部分ruby关于内存使用的三点,具体如何优化使用,大家可以参考原文。

对象的保留

Ruby占用内存最明显的原因是对象的遗留。 Ruby是不会回收静态变量的,所以如果一个静态变量引用了一个对象,那么这个对象也是不会被回收的。

# Ruby 2.2.2

#module GC is supported by ruby2.1+ 
#parameter :total_freed_objects is supported by ruby2.2.2+
GC.start
before = GC.stat(:total_freed_objects)

RETAINED = []
100_000.times do
  RETAINED << "a string"
end

GC.start
after = GC.stat(:total_freed_objects)
puts "Objects Freed: #{after - before}"

# => "Objects Freed: 6
# => "My result is 0~7"
GC.start
before = GC.stat(:total_freed_objects)

100_000.times do
  foo = "a string"
end

GC.start
after = GC.stat(:total_freed_objects)
puts "Objects Freed: #{after - before}"

# => "Objects Freed: 100005
# => "my result is 99999~100006"

综上可以看出,静态变量占用的内存是不会被释放的,除此之外基于全局的对象都不会被垃圾机制收集,比如静态变量、全局变量、modules、classes。所以引用对象的时候要注意是否为全局对象。

对象的复用

以ruby内建string为例,其采取的策略不是反复的创建对象,而是保留之前的对象并复用。比如当你调用string.freeze方法时,ruby会认为这个字符串暂时不会发生修改,就会保留复用他。

RETAINED = []
100_000.times do
  RETAINED << "a string".freeze
end

puts GC.stat(:total_allocated_objects)
# => allocated memory is 42290
RETAINED = []
100_000.times do
  RETAINED << "a string"
end

puts GC.stat(:total_allocated_objects)
# => allocated memory is 142282

上面的例子可以看出,当你调用了freeze方法的时候,ruby不会为每一个string创建对象,而是用之前创建过的对象做多个引用,这样会节省很大一部分内存。

临时的对象

其实很多对象都是临时的,比如如下代码中:

User.where(name: "schneems").first

这条查询语句本身会需要很多对象,用来存储结果的hash,用来存储表名的string以及调用sql语句的时候涉及到的更细节的对象,但是这些对象大多数都不会长时间存储的,所以我们也不必十分在意这样的对象。

共收到 7 条回复

👍 楼主天天放大招

请问这方面内容主要在哪里有得看?

楼主很多都是从 Schneeman 这篇文章来的吧,为什么不注明呢。。 http://www.sitepoint.com/ruby-uses-memory/

#5楼 @tony612 是的,只取了前面一部分。。。简单的说明了下,因为并不会翻译

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册