cas*_*sey 9 sockets memory perl performance multithreading
我正在运行一个包含10个线程的Perl服务器.它们永远不会在程序退出之前被销毁,但这是我打算尽可能多的正常运行时间,所以这就是为什么这对我来说是一个问题.线程多次处理一个简单的任务.当我启动服务器并启动所有线程时,我发现我有288.30 MB的空闲时间.经过每个线程的几次迭代后,它报告285.96 MB空闲.这并不是那么糟糕.可能只是在这些迭代过程中,一些堆栈空间被分配或者某些东西.但是15分钟后,可用内存下降到248.24 MB!我的记忆发生了什么?现在,有趣的是,它已达到稳定水平.它继续慢慢消耗,但不像最初那么快.
我在线程的每次迭代之后打印出可用空间,这样我就可以慢慢看到它.现在有趣的是它不会每次都减少.有时,迭代后空闲内存保持不变.
我正在使用从Linux 2.6上的源代码构建的Perl 5.8.8
有没有人有任何想法,甚至建议可能导致这种情况的原因是什么?我正在考虑将我的Perl升级到更高版本以排除Perl核心内部的内存泄漏.
更新:这可能是一个线程堆栈大小问题?我可以为堆栈分配比我需要的更多内存吗?当我创建我的线程时,我不会更改默认设置.我是不是该?线程doc说默认值通常为16MB,具体取决于系统.16x10线程= 160MB - >这可能是罪魁祸首.思考?
更新:我构建并安装了Perl 5.12.1并重建了模块和所有内容.已经运行了大约一个小时的脚本,这是我注意到的.内存使用现在可以管理,但并不理想.
还有其他想法吗?我可以试试吗?我已经无法解决所有变数了.
更新:我真的想继续使用glibc重新编译Perl作为最后的手段,因为我发现一些报告,在某些版本的Linux上会出现段错误.所以自从我上次发布以来,我进一步探讨了哈希中循环的可能性.一无所获.所以我花了最后几天分析我的子程序并缓存在另一次迭代中使用的任何东西.每次都会重新创建很多新东西,而Perl并没有清理所有内容,即使我明确地解决了这一切.所以如果它不合作,我就不会破坏它.将看看缓存我的对象是否有帮助.稍后会发布内存使用情况统计信息.
更新:嗯,非常奇怪.即使在缓存我的数据以便以后重用之后,内存也会以大致相同的速率上升.它现在开始更高,因为我正在缓存,但随后它继续上升,即使它主要是使用我的缓存对象.这令人费解.猜猜是时候尝试一下glibc ......否则这只是选择Perl的一个缺点,并且必须每隔几天重新启动一次服务器.
更新:尝试没有缓存,没有glibc,再次.工作正常一段时间,几个小时,然后它开始增长.只是想让你看到一个图表.
http://tinypic.com/r/311nc08/3
http://i32.tinypic.com/311nc08.jpg
更新:这是一个日志的摘录,记录每个线程在大约一分钟之前和之后的可用内存.也许这可以帮助别人更好地理解问题.它看起来有点稳定,然后每隔一段时间就会吃掉更多的内存.在这里,我失去了近40 MB!
[9:8:30, Fri Jul 23, 2010] [0] Memory usage at end thread 1: 253.812736MB (obj cache: 136)
[9:8:30, Fri Jul 23, 2010] [0] Memory usage at idle thread 1: 253.812736MB (obj cache: 136)
[9:8:34, Fri Jul 23, 2010] [204] Sending data to thread
[9:8:34, Fri Jul 23, 2010] [0] 3 - Creating a new obj
[9:8:34, Fri Jul 23, 2010] [206] Sending data to thread
[9:8:34, Fri Jul 23, 2010] [0] 4 - Creating a new obj
[9:8:35, Fri Jul 23, 2010] [0] Memory usage at end thread 3: 253.812736MB (obj cache: 136)
[9:8:35, Fri Jul 23, 2010] [0] Memory usage at idle thread 3: 253.812736MB (obj cache: 136)
[9:8:35, Fri Jul 23, 2010] [0] Memory usage at end thread 4: 253.812736MB (obj cache: 136)
[9:8:35, Fri Jul 23, 2010] [0] Memory usage at idle thread 4: 253.812736MB (obj cache: 136)
[9:8:41, Fri Jul 23, 2010] [225] Sending data to thread
[9:8:41, Fri Jul 23, 2010] [0] 2 - Creating a new obj
[9:8:42, Fri Jul 23, 2010] [0] Memory usage at end thread 2: 253.681664MB (obj cache: 136)
[9:8:42, Fri Jul 23, 2010] [0] Memory usage at idle thread 2: 253.681664MB (obj cache: 136)
[9:8:47, Fri Jul 23, 2010] [243] Sending data to thread
[9:8:47, Fri Jul 23, 2010] [0] 1 - Creating a new obj
[9:8:48, Fri Jul 23, 2010] [0] Memory usage at end thread 1: 253.935616MB (obj cache: 136)
[9:8:48, Fri Jul 23, 2010] [0] Memory usage at idle thread 1: 253.935616MB (obj cache: 136)
[9:9:1, Fri Jul 23, 2010] [277] Sending data to thread
[9:9:1, Fri Jul 23, 2010] [0] 3 - Creating a new obj
[9:9:2, Fri Jul 23, 2010] [280] Sending data to thread
[9:9:2, Fri Jul 23, 2010] [0] 4 - Creating a new obj
[9:9:2, Fri Jul 23, 2010] [0] Memory usage at end thread 3: 253.935616MB (obj cache: 136)
[9:9:2, Fri Jul 23, 2010] [0] Memory usage at idle thread 3: 253.935616MB (obj cache: 136)
[9:9:3, Fri Jul 23, 2010] [283] Sending data to thread
[9:9:3, Fri Jul 23, 2010] [0] 2 - Creating a new obj
[9:9:4, Fri Jul 23, 2010] [284] Sending data to thread
[9:9:4, Fri Jul 23, 2010] [0] 1 - Creating a new obj
[9:9:4, Fri Jul 23, 2010] [0] Memory usage at end thread 2: 253.935616MB (obj cache: 136)
[9:9:4, Fri Jul 23, 2010] [0] Memory usage at idle thread 2: 253.935616MB (obj cache: 136)
[9:9:5, Fri Jul 23, 2010] [287] Sending data to thread
[9:9:5, Fri Jul 23, 2010] [0] 3 - Creating a new obj
[9:9:5, Fri Jul 23, 2010] [0] Memory usage at end thread 4: 253.93152MB (obj cache: 136)
[9:9:5, Fri Jul 23, 2010] [0] Memory usage at idle thread 4: 253.93152MB (obj cache: 136)
[9:9:6, Fri Jul 23, 2010] [290] Sending data to thread
[9:9:6, Fri Jul 23, 2010] [0] 2 - Creating a new obj
[9:9:7, Fri Jul 23, 2010] [0] Memory usage at end thread 3: 253.804544MB (obj cache: 136)
[9:9:7, Fri Jul 23, 2010] [0] Memory usage at idle thread 3: 253.804544MB (obj cache: 136)
[9:9:7, Fri Jul 23, 2010] [0] Memory usage at end thread 1: 253.804544MB (obj cache: 136)
[9:9:7, Fri Jul 23, 2010] [0] Memory usage at idle thread 1: 253.804544MB (obj cache: 136)
[9:9:9, Fri Jul 23, 2010] [0] 4 - Creating a new obj
[9:9:9, Fri Jul 23, 2010] [301] Sending data to thread
[9:9:9, Fri Jul 23, 2010] [0] 3 - Creating a new obj
[9:9:9, Fri Jul 23, 2010] [302] Sending data to thread
[9:9:9, Fri Jul 23, 2010] [0] 1 - Creating a new obj
[9:9:10, Fri Jul 23, 2010] [0] 3 - Creating a new obj
[9:9:11, Fri Jul 23, 2010] [0] 3 - Creating a new obj
[9:9:11, Fri Jul 23, 2010] [0] Memory usage at end thread 4: 253.93152MB (obj cache: 136)
[9:9:11, Fri Jul 23, 2010] [0] Memory usage at idle thread 4: 253.93152MB (obj cache: 136)
[9:9:12, Fri Jul 23, 2010] [308] Sending data to thread
[9:9:12, Fri Jul 23, 2010] [0] 4 - Creating a new obj
[9:9:13, Fri Jul 23, 2010] [0] Memory usage at end thread 1: 253.804544MB (obj cache: 136)
[9:9:13, Fri Jul 23, 2010] [0] Memory usage at idle thread 1: 253.804544MB (obj cache: 136)
[9:9:14, Fri Jul 23, 2010] [0] Memory usage at end thread 4: 253.804544MB (obj cache: 136)
[9:9:14, Fri Jul 23, 2010] [0] Memory usage at idle thread 4: 253.804544MB (obj cache: 136)
[9:9:14, Fri Jul 23, 2010] [0] Memory usage at end thread 3: 253.93152MB (obj cache: 136)
[9:9:14, Fri Jul 23, 2010] [0] Memory usage at idle thread 3: 253.93152MB (obj cache: 136)
[9:9:15, Fri Jul 23, 2010] [313] Sending data to thread
[9:9:15, Fri Jul 23, 2010] [0] 1 - Creating a new obj
[9:9:16, Fri Jul 23, 2010] [0] Memory usage at end thread 2: 214.482944MB (obj cache: 136)
[9:9:16, Fri Jul 23, 2010] [0] Memory usage at idle thread 2: 214.482944MB (obj cache: 136)
[9:9:16, Fri Jul 23, 2010] [315] Sending data to thread
[9:9:16, Fri Jul 23, 2010] [0] 4 - Creating a new obj
[9:9:17, Fri Jul 23, 2010] [0] Memory usage at end thread 1: 214.355968MB (obj cache: 136)
[9:9:17, Fri Jul 23, 2010] [0] Memory usage at idle thread 1: 214.355968MB (obj cache: 136)
[9:9:18, Fri Jul 23, 2010] [316] Sending data to thread
[9:9:18, Fri Jul 23, 2010] [0] 3 - Creating a new obj
[9:9:18, Fri Jul 23, 2010] [317] Sending data to thread
[9:9:18, Fri Jul 23, 2010] [0] 2 - Creating a new obj
[9:9:18, Fri Jul 23, 2010] [318] Sending data to thread
[9:9:18, Fri Jul 23, 2010] [0] 1 - Creating a new obj
[9:9:19, Fri Jul 23, 2010] [0] Memory usage at end thread 4: 214.355968MB (obj cache: 136)
[9:9:19, Fri Jul 23, 2010] [0] Memory usage at idle thread 4: 214.355968MB (obj cache: 136)
[9:9:19, Fri Jul 23, 2010] [0] Memory usage at end thread 1: 214.355968MB (obj cache: 136)
[9:9:19, Fri Jul 23, 2010] [0] Memory usage at idle thread 1: 214.355968MB (obj cache: 136)
[9:9:20, Fri Jul 23, 2010] [0] Memory usage at end thread 3: 214.482944MB (obj cache: 136)
[9:9:20, Fri Jul 23, 2010] [0] Memory usage at idle thread 3: 214.482944MB (obj cache: 136)
[9:9:20, Fri Jul 23, 2010] [0] Memory usage at end thread 2: 214.482944MB (obj cache: 136)
[9:9:20, Fri Jul 23, 2010] [0] Memory usage at idle thread 2: 214.482944MB (obj cache: 136)
Run Code Online (Sandbox Code Playgroud)
更新(2010年8月12日):使用带有线程和系统malloc的新编译的Perl 5.12版本运行它一天.奇怪的是我得到了同样的行为.慢慢地一次丢失大块的MB.可能会尝试Valgrind,看看为什么我会失去它.我正在玩别的东西,虽然我想到别的东西.我的脚本创建并销毁(据称)许多SSL套接字.诸如IO :: Socket :: SSL之类的广泛使用的模块是否有可能泄漏一点?或者也许是OpenSSL?(使用v0.9.8o).要尝试同步对SSL模块的访问以查看它是否有任何影响,可能会遇到线程访问它的问题.
更新:尝试在每个线程内单独加载模块,更快地占用内存.尝试使用套接字函数锁定区域,因此一次只有一个线程使用它们,仍然会像以前一样丢失内存.使用完全相同的工作量将工作线程数从4增加到10.记忆没有持续30分钟.让我相信它是内部的Perl问题,它的线程实现,或堆栈问题(没有双关语意).我尝试使用内置的线程方法更改堆栈大小,但结果相同.要寻找另一种方式.也许是一种较低级别的方式 增加线程数会使内存变得更快......似乎是线程的堆栈实现或堆栈的大小
更新(2010年9月15日):在IO :: Socket :: SSL doc中找到这个有趣的小故事......
这是因为需要循环引用以使IO :: Socket :: SSL套接字同时像对象和glob引用一样起作用.
"循环参考"吧?另一个可能的解释是,即使我明确地取消了这些插座,这些插座都会坚持一段时间.打算看看Weaken,看看是否对插座做了什么.如果我发现任何有趣的东西会让你知道.
已解决(2010年9月16日):查看我发布的包含解决方案的答案
Eva*_*oll 15
你的Perl已经4岁半了.升级到5.12.只需搜索5.12构建说明,看看它有哪些主要线程改进,可能只是神奇地修复你的模糊问题:
我的意思是当你谈到四年的开发以及可能导致这个问题的各种各样的东西时,列表就会继续下去,查看现代的更新日志::: 共享
我评论了你的帖子,这将是我的下一组建议:如果你没有使用glibc而你正在使用perl malloc(默认),你将永远不会向操作系统释放内存.进程大小将代表perl每个占用的最大大小.尝试使用glibc malloc进行重建(需要重新编译),看看是否提供了不同的内存配置文件.除此之外,是时候展示代码了.
最后钉了泄漏.首先,我想向您展示改进.您不应该查看实际数字,因为自第一张图表以来用户群已经增加,只需查看斜率的差异.
之前的内存使用情况图:http://i32.tinypic.com/311nc08.jpg
内存使用情况图:http://i51.tinypic.com/29goill.jpg
几个月来,我每隔几天就无法重启服务器,但在过去的14个小时里,内存使用量没有增加.
我用来帮助开发服务器的每个教程,示例,演示文稿和书籍都省略了一个关于IO :: Socket :: SSL的非常重要的事实.每个在线程应用程序中使用该模块的人都会更好地倾听.没有人曾经强调IO :: Socket :: SSL文档中的最后一行,这让我非常愚蠢地假设我创建的任何套接字,就像几乎任何其他数据结构一样,一旦超出范围就会被释放(并且是的) ,我确实知道该规则的例外情况).我以为我会帮助每个人,并呼唤我指的那条线.
... IO :: Socket :: SSL套接字将保持打开状态,直到程序结束或您明确关闭它们.这是因为需要循环引用以使IO :: Socket :: SSL套接字同时像对象和glob引用一样起作用.
http://search.cpan.org/dist/IO-Socket-SSL/SSL.pm#LIMITATIONS
我从来没有意识到这些插座中有一个循环引用的事实,如果我不知道它们,那么我读过的每个人的博客和书籍都不知道(因此呼出).
所以你可以想象,这有一个非常简单的解决方案.在我的线程的工作循环中,每次迭代都会创建一个套接字,我只需eval { close $socket; };undef $socket;在底部放置一个以确保它在处理下一个客户端之前关闭.我启动了我的服务器并等待并观察内存使用率是否稳定,如我在第二张图中所示.因此,在对此问题进行两个月的故障排除后,我终于找到了解决方案.我希望这为任何其他业余爱好者使用套接字编程提供了一些见解.感谢所有提供答案/意见/建议的人,每一点都有所帮助,这有助于有一个地方反弹意见.