我正在处理一个遗留系统(Ruby 2.7.6),它遭受了内存泄漏,这导致以前的开发人员使用puma worker killer,它通过每30分钟重新启动一次进程来克服内存问题。随着流量的增加,我们现在需要增加示例的数量,并将30分钟的死亡率降低到甚至20分钟。
我们想调查一下这个内存泄漏的来源,它显然源于我们的许多Gem依赖项之一(以前的开发人员提供的信息)。
这个系统是在AWS(Elastic Beanstalk)上运行的,但是也可以在Docker上运行。有谁能推荐一个好的工具,并指导如何找到这个内存泄漏的来源吗?谢谢
- 更新:我使用了mini-profiler,并拍摄了一些内存快照,以查看大约100个请求对服务器的影响,[之前,期间,之后]
从输出来判断,Ruby中似乎没有内存泄漏,但内存使用确实增加并保持不变,尽管似乎没有被我们使用...
- 之前**:
KiB内存:总计2007248个,628156个可用,766956个已用,612136个缓冲区/缓存KiB交换:总计2097148,2049276可用,47872已使用。1064852可用内存
分配总额:115227字节(1433个对象)保留的总字节数:21036字节(147个对象)
gem分配的内存
33121 activesupport-6.0.4.7
21687 actionpack-6.0.4.7
14484 activerecord-6.0.4.7
12582 var/app
9904 ipaddr
6957 rack-2.2.4
3512 actionview-6.0.4.7
2680 mysql2-0.5.3
1813 rack-mini-profiler-3.0.0
1696 audited-5.0.2
1552 concurrent-ruby-1.1.10
- 期间**:
KiB内存:总计2007248个,65068个可用,1800424个已用,141756个缓冲区/缓存KiB交换:总计2097148,免费2047228,已使用49920。
58376可用内存
分配总额:225272583字节(942506个对象)保留的总字节数:1732241字节(12035个对象)
gem分配的内存
106497060最大意识数据库-1.0.0
58308032精神科
38857594用户代理解析器-2.7.0
4949108活动支持-6.0.4.7
3967930其他
3229962活动记录-6.0.4.7
2154670样品架-2.2.4
1467383行动包-6.0.4.7
1336204活性成分模型-6.0.4.7
- 之后:**
KiB内存:总计2007248个,73760个可用,1817688个已用,115800个缓冲区/缓存KiB交换:总计2097148,免费2032636,已使用64512。
54448可用内存
分配总额:109563字节(1398个对象)保留的总字节数:14988字节(110个对象)
gem分配的内存
29745 activesupport-6.0.4.7
21495 actionpack-6.0.4.7
13452 activerecord-6.0.4.7
12502 var/app
9904 ipaddr
7237 rack-2.2.4
3128 actionview-6.0.4.7
2488 mysql2-0.5.3
1813 rack-mini-profiler-3.0.0
1360 audited-5.0.2
1360 concurrent-ruby-1.1.10
那漏洞会在哪里,是彪马吗?
1条答案
按热度按时间ar7v8xwq1#
从问题中的统计数据来看,大多数对象都被内存分配器正确地释放了。
但是,当您有很多重复的分配时,系统的
malloc
有时(而且经常)会占用内存而不将其释放给系统。这样做有两个主要原因:
1.最重要的是:heap fragmentation(分配器无法释放内存,也无法将部分内存用于将来的分配)。
1.系统的内存分配器知道它可能很快会再次需要这些内存(这与可以释放并且不会受到碎片影响的内存部分有关)。
这个问题可以通过尝试将系统的内存分配器替换为针对您的特定需求而调优的分配器(即
jamalloc
,如建议的here和here,以及询问有关here的问题)来解决。在使用C扩展时,您还可以尝试使用具有自定义内存分配器的gem(
iodine
gem就是这样做的,但您也可以让其他gem也这样做)。这种方法应该有助于缓解这个问题,但事实是,您的一些gem似乎内存不足...我的意思是...:
maxmind-db
gem是否使用了106,497,060字节(106MB)的内存,或者它是否分配了该数量的对象?psych
如此饥渴?数据和YAML之间是否有可以跳过的往返?user_agent_parser
gem)...也许你可以缓存这些字符串,而不是有很多重复的。例如,你可以把这些字符串组成一个Set
,并用Set中的对象替换每个String对象,这样相等的字符串就指向同一个对象(防止某些对象重复并释放一些内存)。"是彪马吗"
也许不会。
虽然我是
iodine
web服务器的作者,但我真的很喜欢Puma团队多年来所做的工作,认为这是一个非常可靠的服务器,我真的怀疑漏洞是来自服务器,但你总是可以切换,看看会发生什么。