我有一个运行了一系列的实验,没有打算将数据从一个存储测试到另一个Python程序。 我的代码中包含了内存泄漏对此我完全找不到(我看其它线程内存泄漏)。 由于时间的限制,我不得不放弃寻找泄漏,但如果我能每个实验隔离,该程序可能会运行足够长的时间来产生我需要的结果。
- 将运行在一个单独的线程的帮助每个测试?
- 是否有隔离泄漏的影响的任何其他方法?
具体情况详细
- 我的代码有两个部分:实验亚军和实际的实验代码。
- 虽然没有全局被代码之间共享用于运行所有实验和由每个实验中使用的码,一些类/功能必然共享。
- 实验亚军不仅是循环的简单,可轻松放入shell脚本。 它首先决定在其上需要运行给定的配置参数的试验中,然后运行测试然后以特定的方式输出该数据。
- 我手动打过电话的垃圾收集器的情况下,问题只是认为,垃圾收集不运行的,但是这并不工作
更新
Gnibbler的回答实际上已经让我发现,其中存储所有每次计算中使用的数据我ClosenessCalculation对象没有被杀死。 然后我用的是手动删除一些链接,这似乎有固定的内存问题。
您可以使用这样的事情来帮助跟踪内存泄漏
>>> from collections import defaultdict
>>> from gc import get_objects
>>> before = defaultdict(int)
>>> after = defaultdict(int)
>>> for i in get_objects():
... before[type(i)] += 1
...
现在假设测试泄密一些内存
>>> leaked_things = [[x] for x in range(10)]
>>> for i in get_objects():
... after[type(i)] += 1
...
>>> print [(k, after[k] - before[k]) for k in after if after[k] - before[k]]
[(<type 'list'>, 11)]
11,因为我们已经泄漏含10多个列表一个列表
线程不会帮助。 如果你必须放弃在发现泄漏,那么唯一的解决办法,以遏制其效果是在同时运行一个新的进程一次(例如,当测试已经离开整体的内存消耗太高,自己的喜好-可以判断VM大小轻松阅读/proc/self/status
在Linux中,和其他类似的方法对其他操作系统的)。
确保整个脚本有一个可选的参数来告诉它的测试号(或其他测试识别)从启动,这样当该脚本的一个实例决定它占用了太多的内存,它可以告诉它的后继者从哪里重新开始。
或者,更扎实,确保每个测试完成它的标识被附加到某些文件,一个众所周知的名字。 当程序启动时,它首先读取该文件,从而知道哪些测试已经运行。 这种体系结构是更加牢固,因为它也包括其中测试期间程序崩溃的情况下; 当然,要完全自动从这样的崩溃恢复,你需要一个独立的监督程序和流程,负责启动测试程序的一个新的实例时,它决定了前一个已崩溃(它可以使用subprocess
为宗旨 - 它也需要一种方法来告诉序时完成,从测试程序如正常的退出可能意味着,虽然任何崩溃或退出一个状态= 0表示需要启动一个新的新鲜实例)!
如果这些架构提出上诉,但您需要执行这些进一步的帮助,只是发表评论这个答案,我会很乐意提供示例代码 - 我不想做“先发制人”的情况下,有作为的尚未表达出来的问题使该架构不适合你。 (这也可能有助于知道你需要运行哪些平台)。
我有同样的问题与第三方C库这是漏水。 我能想到的最清洁的工作,周围是叉子和等待。 它的好处是,你甚至不必每次运行后创建一个单独的进程。 您可以定义批处理的大小。
这里有一个通用的解决方案(如果你发现泄漏,你需要做的唯一改变是改变run()的调用run_single_process()而不是run_forked(),你会做):
import os,sys
batchSize = 20
class Runner(object):
def __init__(self,dataFeedGenerator,dataProcessor):
self._dataFeed = dataFeedGenerator
self._caller = dataProcessor
def run(self):
self.run_forked()
def run_forked(self):
dataFeed = self._dataFeed
dataSubFeed = []
for i,dataMorsel in enumerate(dataFeed,1):
if i % batchSize > 0:
dataSubFeed.append(dataMorsel)
else:
self._dataFeed = dataSubFeed
self.fork()
dataSubFeed = []
if self._child_pid is 0:
self.run_single_process()
self.endBatch()
def run_single_process(self)
for dataMorsel in self._dataFeed:
self._caller(dataMorsel)
def fork(self):
self._child_pid = os.fork()
def endBatch(self):
if self._child_pid is not 0:
os.waitpid(self._child_pid, 0)
else:
sys.exit() # exit from the child when done
这种隔离内存泄漏子进程。 它永远不会比BATCHSIZE变量的值泄漏多次。
我只想重构实验成单独的功能(如果不喜欢的话),然后接受它调用一次实验功能的命令行的实验数量。
刚刚bodgy一个shell脚本如下:
#!/bin/bash
for expnum in 1 2 3 4 5 6 7 8 9 10 11 ; do
python youProgram ${expnum} otherParams
done
这样一来,你可以离开大部分代码原样,这将清除出你认为你在每个实验之间的任何内存泄漏。
当然,最好的办法是经常发现和解决问题的根本原因,但是,正如你已经指出,这不是一个选择。
虽然这是很难想象在Python内存泄漏,我要在那一个你的话 - 你可能要至少认为你错在那里的可能性,但是。 考虑提高在一个单独的问题,值得我们能够在低优先级上工作(而不是这种速战速决的版本)。
更新:因为这个问题使社区维基已经从原来的有所改变。 我删除了答案,但一个事实,我仍然认为这是有益的 - 你可以做同样的实验亚军,我提出了bash脚本,你只需要确保实验是独立的进程,使内存泄漏不发生(如果内存泄漏的亚军,你将不得不做的根本原因分析和正确修复bug)。