我们有什么策略来保持较低的内存使用率?
Ruby确实需要大量内存,但也值得每一点。
我们如何使内存使用率保持低水平?我们是否避免使用大字符串,而是使用较小的数组/哈希,还是为我们担心并让垃圾收集器完成这项工作没有问题?
编辑:我在这里找到了一篇有关此主题的不错的文章,但仍然很有趣。
解决方案
我不是红宝石开发人员,但我认为某些技术和方法适用于任何语言:
使用适合工作的最小尺寸变量
不用时销毁并关闭变量和连接
但是,如果我们有一个对象,则需要多次使用,请考虑将其保持在范围内
操纵大字符串的任何循环dp在较小的字符串上工作,然后追加到较大的字符串
使用体面的(最后尝试捕获)错误处理来确保对象和连接已关闭
处理数据集时,仅返回必要的最小值
我是Ruby的新手,但到目前为止,我还没有发现在这方面做任何特别的事情的必要性(也就是说,超出了我通常作为程序员所做的工作)。也许是因为内存比认真优化内存所需的时间便宜(我的Ruby代码在具有4-12 GB RAM的计算机上运行)。也可能是因为我正在使用它的作业不是长时间运行的(即,它将取决于应用程序)。
我发现Phusion的Ruby Enterprise Edition(主线Ruby的一个分支,垃圾收集得到了很大的改进)在内存使用方面产生了巨大的变化……而且,它们使安装(和删除,如果我们很容易地)变得异常容易找到需要)。
我们可以找到更多信息并将其下载到他们的网站上。
除了在极端情况下之外,无需担心内存使用情况。我们花费在减少内存使用上的时间将购买很多GB。
我真的认为这没什么大不了的。
为了减少内存消耗,使代码的可读性降低,只有在需要时才应该这样做。根据需要,我的意思是针对性能概要文件有特定的用例,并有特定的指标来指示任何更改都可以解决该问题。
如果我们有一个应用程序,内存将成为限制因素,那么Ruby可能不是最佳选择。也就是说,我发现我的Rails应用程序通常每个Mongrel实例消耗大约40-60mb的RAM。从事物的角度来看,这不是很多。
我们也许可以使用JRuby在JVM上运行应用程序,但Ruby VM目前不如用于内存管理和垃圾收集的JVM先进。 1.9版本增加了许多改进,并且正在开发替代VM。
我尝试将数组,列表和数据集保持尽可能的小。单个对象无关紧要,因为在大多数现代语言中,创建和垃圾回收都非常快。
在这种情况下,我们必须从数据库中读取某种庞大的数据集,请确保以向前/仅方式读取并进行少量处理,而不是先将所有内容加载到内存中。
- 选择有效的表示形式,可以很好地缩放并执行我们需要的日期结构。
- 使用可以使用有效数据结构运行的算法,而不是ated肿但容易的算法。
- 看别的地方。 Ruby有一个C桥,与Ruby相比,它在C中更容易成为内存意识的对象。
查看具有有限内存的系统的小型内存软件模式。我们没有指定哪种内存限制,但我假设使用RAM。虽然不是特定于Ruby的,但我认为我们会在本书中找到一些有用的想法,这些模式涵盖RAM,ROM和辅助存储,并分为小数据结构,内存分配,压缩,辅助存储和小型体系结构的主要技术。 。
我们曾经拥有过的唯一真正值得担心的是RMagick。
解决方案是确保我们使用的是RMagick版本2,并在使用完图像后调用Image#destroy!
。
避免这样的代码:
str = '' veryLargeArray.each do |foo| str += foo # but str << foo is fine (read update below) end
这将创建每个中间字符串值作为String对象,然后在下一次迭代时删除其唯一引用。这增加了成堆的不断增加的字符串,这些字符串必须被垃圾回收,从而浪费了内存。
相反,请使用Array#join
:
str = veryLargeArray.join('')
这在C中非常有效地实现,并且不会产生String创建开销。
更新:乔纳斯(Jonas)在下面的评论中正确。我的警告适用于" + =",而不适用于" <<"。
我正在使用Python,但是我猜想它们的策略是相似的。
我尝试使用小的函数/方法,以便当我们返回调用方时,本地变量会自动进行垃圾回收。
在较大的函数/方法中,当不再需要大型临时对象(如列表)时,我会明确删除它们。尽早关闭资源可能也会有所帮助。