Ubuntu Ruby在Rails应用程序中解决内存泄漏问题
在向大家详细介绍Ubuntu Ruby之前,首先让大家了解下Ubuntu Ruby,然后全面介绍Ubuntu Ruby,希望对大家有用。
Rails应用程序的内存泄漏问题和解决
内存泄漏是服务器端程序经常遇到的,有时候内存泄漏问题会让人很头疼,总体来说,Rails的内存泄漏问题比Java要少得多,这是因为Java内存泄漏最常见的三种情况在Rails当中不存在:
1、HttpSession导致的内存泄漏
Java程序员喜欢往session里面丢很多东西,最糟糕的是竟然有很多框架软件也肆无忌惮往session里面丢状态数据,但Rails的session是不放在内存里面的,所以无此烦恼。
2、数据库连接释放不彻底
Java的数据库连接池释放不彻底,以及查询游标释放不彻底,都必然导致内存泄漏。Rails没有数据库连接池,而是每个进程持有一个长连接,因此不存在这个问题,而且由于持有长连接,也不存在Java里面的OpenSessionInView的烦恼。
3、用静态变量持有全局共享数据
Java程序员很喜欢通过静态全局变量来持有共享数据,但共享数据忘记清理的话,也很容易导致内存泄漏,Ubuntu Ruby是SNA架构,多进程服务器模式,进程间无法共享数据,反而避免了全局共享数据带来的麻烦。
但是Rails应用有一种情况:在Ubuntu Ruby代码中调用C写的第三方Ubuntu Ruby类库的时候,很容易导致内存泄漏,但这种内存泄漏反而在Java中极其罕见。Ubuntu Ruby本身有GC来管理内存堆,但是代码一旦调用C写的第三方Ubuntu Ruby类库,内存堆的分配权就掌握在第三方C库的实现上面了,如果这个C库的代码质量不够好,内存泄漏就不可避免。
由于Ubuntu Ruby本身性能很差,因此计算量大的功能往往依赖底层的C库来实现,这下内存泄漏的潘多拉魔盒就打开了!而Java性能比较好,功能都是纯Java编写,基本上看不到需要依赖第三方C库的情况,因此比较安全。
JavaEye也面临着内存泄漏的困扰,这方面困扰主要来自于Rmagic。Rmagick调用ImageMagick的C库来完成图片的操作,从我们的监测来看,RMagick大多数情况下会缓慢的泄漏内存,在某些特定的图片操作上会急剧的泄漏内存。
解决办法就是用mini_magick替代Rmagick,mini_magick是直接调用ImageMagick的mogrify命令,另起一个进程来操作图片,操作完进程就结束了,绝无后患,由于Linux的fork进程开销不大,因此也不必担心性能问题。
此外,调用第三方C库的Ubuntu Ruby代码编写都需要高度小心,比方说JavaEye使用ferret实现全文检索,根据应用的需要调用ferret的API来编写自己的analyzer,其中在实现token_stream方法上面使用了XXXAnalyzer.new和XXXToken.new,XXXFilter.new,
结果内存急剧泄漏,经过检查发现是Analyzer对象不能被反复创建,改成创建后缓存该对象就好了,但是Filter和Token对象却必须每次创建,此外ferret的PerAnalyzerFilter也有内存泄漏问题。由于类库是用C编写的,单纯看API文档或者看源代码片断一般无法判断出里面的内存泄漏陷阱的。
当遇到了难以解决和定位的内存泄漏问题,Ubuntu Ruby也有类似Java的内存Profiler工具:
1、Memory Profiler
一个纯Ubuntu Ruby编写的内存探测器,原理很简单,就是用Ubuntu Ruby的对象引用计数器ObjectSpace.each_object去遍历内存堆中的每个Ubuntu Ruby对象,进行统计和分析。用起来很简单,非常适合于开发环境下侦测内存泄漏问题,但不能用在生产环境下,极度影响Rails性能。