Python中的内存使用:什么';内存分析器和guppy的区别是什么?

Python中的内存使用:什么';内存分析器和guppy的区别是什么?,python,memory-profiling,Python,Memory Profiling,对于特定python脚本的内存使用,我完全感到困惑。我想我真的不知道如何分析使用情况,尽管有几个问题 我的问题是:内存分析器和guppy.hpy之间有什么区别?为什么一个告诉我我在使用大量内存,而另一个告诉我我没有使用? 我正在使用pysam,一个用于访问生物信息学SAM/BAM文件的库。我的主脚本在将SAM(ASCII)转换为BAM(二进制)并处理其间的文件时,内存很快就会耗尽 我创建了一个小测试示例,以了解在每个步骤中分配了多少内存 # test_pysam.py: import pys

对于特定python脚本的内存使用,我完全感到困惑。我想我真的不知道如何分析使用情况,尽管有几个问题

我的问题是:内存分析器
guppy.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
decorator并取消注释
guppy
相关行,我得到以下输出(
python test_pysam.py
):

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

memory_profiler和guppy.hpy之间有什么区别

您了解堆的内部视图和程序的操作系统外部视图之间的区别吗?(例如,当Python解释器在1MB上调用
free
时,由于多种原因,它不会立即或甚至可能永远向操作系统返回1MB的页面。)如果你这样做,那么答案很简单:内存分析器会询问操作系统对内存的使用情况;guppy正在从堆结构内部进行计算

除此之外,memory_profiler还有一个特性guppy不会自动检测您的函数,以便在每行代码之后打印报告;它在其他方面更简单、更容易,但灵活性较差。如果你知道你想做什么,而memory_profiler似乎做不到,它可能做不到;有了guppy,也许它可以,所以研究一下文档和来源

为什么一个告诉我我在使用大量的内存,而另一个告诉我我没有

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

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

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

我应该使用什么过程来正确地分析我更大、更复杂的python程序的每个步骤的内存使用情况


如果您从操作系统的角度询问内存使用情况,memory_profiler正是在做您想要做的事情。虽然深入研究pysam可能很困难,但使用
@profile
装饰器包装一些函数应该是很简单的。然后您将知道哪些C函数负责内存;如果你想更深入地挖掘,你显然必须在C级进行分析(除非samtools文档或samtools社区中有信息)。

注意,“test.sam”位于第二行,因为它是一个更长的名称,一旦我更改了它,我意识到如果我将文件名放在一行,我的行号信息将被关闭。
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