繁体   English   中英

Python 单元测试内存消耗

[英]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 会保留测试方法变量以报告值,或者至少在这种情况下提供关于变量的报告。 我不知道,也许我在这里忽略了一些东西。

但是,我需要摆脱这种多余的内存。 到目前为止,我的选择是:

  • 对我不再需要的任何变量调用 del。 然而,这在某种程度上破坏了垃圾收集器的好东西,并且“不必担心内存问题”
  • 获得更多内存。

我很想听听设置某种标志的可能性。 更重要的是,我很想听到有人指出我犯的一个明显错误,或者有人告诉我使用 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM