为什么我的包占用这么多内存

Why Does My Package Take up so Much Memory

我正在研究 Ptera Software,一种开源空气动力学求解器。这是我分发的第一个包,我遇到了一些与内存管理相关的问题。

具体来说,导入我的包会占用大量内存。我上次检查时,它占用了大约 136 MB 的 RAM。 PyPI 列出包大小为 118 MB,这似乎也高得离谱。作为参考,NumPy 只有 87 MB。

起初,我以为我可能不小心在包中包含了一些大文件。所以我从 PyPI 下载了每个版本的 tar.gz 文件并解压缩了它们。 None 解压超过 1 MB。

这让我相信我导入需求的方式有问题。我的 REQUIREMENTS.txt 文件如下所示:

matplotlib >= 3.2.2, < 4.0.0
numpy >= 1.18.5, < 2.0.0
pyvista >= 0.29.0, < 1.0.0
scipy >= 1.5, < 2.0
numba >= 0.53, <1.0

也可能是我弄乱了 __init__.py 文件。它看起来像这样:

from pterasoftware import aerodynamics
from pterasoftware import airfoils
from pterasoftware import geometry
from pterasoftware import meshing
from pterasoftware import movement
from pterasoftware import operating_point
from pterasoftware import output
from pterasoftware import problems
from pterasoftware import steady_horseshoe_vortex_lattice_method
from pterasoftware import steady_ring_vortex_lattice_method
from pterasoftware import unsteady_ring_vortex_lattice_method

目录结构如下:

├───pterasoftware
│   ├───airfoils
│   │   └───naca0012.dat
│   ├───__init__.py
│   ├───aerodynamics.py
│   ├───geometry.py
│   ├───meshing.py
│   ├───movement.py
│   ├───operating_point.py
│   ├───output.py
│   ├───problems.py
│   ├───steady_horsehoe_vortex_lattice_method.py
│   ├───steady_ring_vortex_lattice_method.py
│   └───unsteady_ring_vortex_lattice_method.py

我知道导入 numpy、matplotlib 和 scipy 等大型包可能会占用大量内存。但是,我知道有很多使用这些资源的包,导入这些资源不会占用将近 136 MB 的空间。我在这里错过了什么?

这是我用来测试导入包时分配的内存的代码:

from memory_profiler import profile


@profile
def find_import_memory_usage():
    import pterasoftware as ps


if __name__ == "__main__":
    find_import_memory_usage()

参见Importing a python module takes too much memory。导入模块需要内存来存储字节码(即 .pyc 文件)以及存储引用对象的编译形式。

那么,分配所有这些内存到底是为了什么?

我们可以通过 运行 您的内存分析器检查是否为您的程序包或您的依赖项分配了内存。我们会先导入你的包的依赖,看看它们占用了多少内存。

由于下次导入这些库时不会分配内存(您可以自己尝试),因此当我们导入您的包时,我们只会看到该包的内存使用情况,而不会看到它的依赖项。

from memory_profiler import profile

@profile
def find_import_memory_usage():
    import matplotlib
    import numpy
    import pyvista
    import scipy
    import numba
    import copy
    import pterasoftware

这给了我(在 Windows 10 上使用股票 Python 3.7.6):

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
    10     18.3 MiB     18.3 MiB           1   @profile
    11                                         def find_import_memory_usage():
    12     34.3 MiB     16.0 MiB           1       import matplotlib
    13     34.3 MiB      0.0 MiB           1       import numpy
    14     96.6 MiB     62.2 MiB           1       import pyvista
    15    101.1 MiB      4.6 MiB           1       import scipy
    16    137.3 MiB     36.2 MiB           1       import numba
    17    137.3 MiB      0.0 MiB           1       import copy
    18    174.6 MiB     37.3 MiB           1       import pterasoftware

你的包只用了37.3MiB,合理多了。 您的依赖项使用 119 MiB,而 Pyvista 是一个特别昂贵的导入。而当使用numpy时,会要求.

ways to reduce the memory requirements 个您自己的包(有些是以牺牲可读性为代价的,有些只是很好的实践,有些在使用像 Numba 这样的即时编译器时可能根本没有帮助) ,但是如果你想减少依赖项占用的内存,那么你可能只需要选择不同的依赖项,或者在最坏的情况下,修改它们的代码以将它们拆分为仅项目需要的组件,如果它们其他组件包含大量未使用的开销。