Python中的内存使用:memory_profiler和guppy有什么区别?

时间:2012-09-21 16:53:46

标签: python memory-profiling

我对特定python脚本的内存使用情况感到非常困惑。我想我真的不知道如何使用来自几个SO问题/ adviceAnswers来分析使用情况。

我的问题是: memory_profilerguppy.hpy之间有什么区别?为什么一个人告诉我我正在使用大量内存,而另一个告诉我我不是?

我正在使用pysam,一个用于访问生物信息学SAM / BAM文件的库。当将SAM(ASCII)转换为BAM(二进制)并操纵其间的文件时,我的主脚本会快速耗尽内存。

我创建了一个小测试示例,以了解每一步分配了多少内存。

# test_pysam.py: 

import pysam
#from guppy import hpy

TESTFILENAME = ('/projectnb/scv/yannpaul/MAR_CEJ082/' +
                'test.sam')
#H = hpy()

@profile # for memory_profiler
def samopen(filename):
#    H.setrelheap()
    samf = pysam.Samfile(filename)
#    print H.heap()
    pass


if __name__ == "__main__":
    samopen(TESTFILENAME)

使用memory_profiler(python -m memory_profiler test_pysam.py)监视内存使用情况会产生以下输出:

Filename: test_pysam.py

Line #    Mem usage    Increment   Line Contents
================================================
    10                             @profile # for memory_profiler
    11                             def samopen(filename):
    12     10.48 MB      0.00 MB   #    print H.setrelheap()
    13    539.51 MB    529.03 MB       samf = pysam.Samfile(filename)
    14                             #    print H.heap()
    15    539.51 MB      0.00 MB       pass

然后评论@profile装饰器并取消注释guppy相关行,我得到以下输出(python test_pysam.py):

Partition of a set of 3 objects. Total size = 624 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0      1  33      448  72       448  72 types.FrameType
     1      1  33       88  14       536  86 __builtin__.weakref
     2      1  33       88  14       624 100 csamtools.Samfile

第13行的总大小在一种情况下为529.03 MB,在另一种情况下为624字节。这里到底发生了什么? 'test.sam'是一个~52MB SAM(同样是一种ASCII格式)文件。深入研究pysam对我来说有点棘手,因为它是与samtools相关的C库的包装器。无论Samfile实际上是什么,我想我应该能够了解分配多少内存来创建它。我应该使用什么程序来正确分析更大,更复杂的python程序的每一步的内存使用情况?

1 个答案:

答案 0 :(得分:7)

  

memory_profiler和guppy.hpy有什么区别?

您是否了解堆的内部视图与操作系统的外部视图之间的区别? (例如,当Python解释器在1MB上调用free时,由于多种原因,它不会立即 - 或者甚至永远 - 将1MB的页面返回到操作系统。)如果这样做,那么答案是很简单:memory_profiler要求操作系统使用你的内存; guppy正在从堆结构内部搞清楚。

除此之外,memory_profiler有一个功能guppy不会自动检测你的功能,以便在每行代码后打印报告;它更简单,更容易但灵活性更低。如果你知道你想要做什么,而且memory_profiler似乎没有这样做,那么它可能不会;用孔雀鱼,也许它可以,所以研究文档和来源。

  

为什么一个人告诉我我正在使用大量内存,另一个告诉我我不是?

很难确定,但这里有一些猜测;答案可能是不止一个的组合:

也许samtools使用mmap将足够小的文件映射到内存中。这会增加页面使用量的大小,但不会增加堆的使用量。

也许samtools或pysam会创建很多可以快速释放的临时对象。你可能有很多碎片(每页只有几个活的PyObjects),或者你的系统的malloc可能已经决定它应该在你的空闲列表中保留很多节点,因为你分配的方式,或者它可能没有返回的页面到操作系统,或操作系统的VM可能没有回收的回收页面。确切的原因几乎总是无法猜测;最简单的方法是假设永远不会返回释放的内存。

  

我应该使用什么程序来正确分析更大,更复杂的python程序的每一步的内存使用情况?

如果您从操作系统的角度询问内存使用情况,memory_profiler正在按照您的意愿执行操作。虽然主要挖掘pysam可能很困难,但使用@profile装饰器包装一些函数应该是微不足道的。然后你就会知道哪些C函数负责内存;如果你想深入挖掘,你显然需要在C级别进行分析(除非有samtools文档或samtools社区的信息)。