[英]Python unittest memory consumption
在使用 python 的 unittest 框架时,我注意到一种行为会导致我的情况出现一些问题。 为了演示它,请查看以下代码:
import unittest
import time
class TC_Memory(unittest.TestCase):
def setUp(self):
unittest.TestCase.setUp(self)
self.__result = False
def test_unittest_mem1(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem2(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem3(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem4(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem5(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem6(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem7(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem8(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
def test_unittest_mem9(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
self.assertTrue(self.__result, "Failed")
if __name__ == "__main__":
unittest.main()
这些测试方法都做同样的事情。 生成一个巨大的列表,等待一秒钟,然后根据 __result 变量通过或失败。
现在,当测试通过时,没有什么大不了的,但是当测试失败时,列表的内存似乎没有被释放。 这会导致巨大的内存消耗,因为每个测试似乎都持有其内存。 最后,在每次测试运行并打印结果后,内存被释放,一切恢复正常。
虽然上面的代码夸大其词,但真实案例包含 200 多个测试,每个测试使用大约 20-30 MB 的内存。 如果这些没有被释放,我就会遇到内存不足的问题。
如果测试失败,似乎 unittest 会保留测试方法变量以报告值,或者至少在这种情况下提供关于变量的报告。 我不知道,也许我在这里忽略了一些东西。
但是,我需要摆脱这种多余的内存。 到目前为止,我的选择是:
我很想听听设置某种标志的可能性。 更重要的是,我很想听到有人指出我犯的一个明显错误,或者有人告诉我使用 python 或 unittest 的 xy 版本不会发生这种情况。
至于使用的版本:它是python 3.3.5 final 64bit
所以,如果还有其他问题,我很乐意回答。 如果您有任何想法,或者在黑暗中拍摄,请让我听到,我会尝试一下。
提前致谢。
问题可能是测试运行器(或结果类)保留了抛出的异常,其中包含对引用大对象的帧的引用。 您可能想要做的是编写一个不显示此行为的自定义运行程序。 类似的东西(对不起 python2,但这是我目前所拥有的):
class CustomTestResult(TextTestResult):
def addError(self, test, err):
tp, vl, tb = err
super(CustomTestResult, self).addError(test, (tp, vl, placeholder))
def addFailure(self, test, err):
tp, vl, tb = err
super(CustomTestResult, self).addFailure(test, (tp, vl, placeholder))
class CustomTestRunner(TextTestRunner):
resultclass = CustamTestResult
if __name__ == "__main__":
import sys
try:
raise Exception
except Exception as err:
placeholder = sys.exc_info()[2]
unittest.main(testRunner = CustomTestRunner)
不过,这里可能还有一些改进的空间。 例如,您可以递归地检查回溯并确定它是否足够大以促使它被替换(甚至可能从帧中删除有问题的对象)。 对于被测代码raise
s 异常的情况尤其如此(在这种情况下,您可能会在回溯中受到关注,而不仅仅是占位符回溯)。
另一种解决方案可能是不在同一堆栈帧中进行分配,因为从失败的测试创建的堆栈帧将仅包含其上的帧。 喜欢:
def mem1(self):
list1 = [9876543210] * 2048*2048*9
time.sleep(1)
def test_unittest_mem1(self):
self.mem1()
self.assertTrue(self.__result, "Failed")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.