5

我正试图控制我的程序内存占用。我想我会从导入开始,因为我只使用了相当大的PyObjC库中的 3-4 个函数。然而,我有点惊讶地看到,导入更大模块的特定部分与实际加载到内存中的内容几乎为零。

内存分析器输出

在 OSX 上加载整个 Quartz.CoreGraphics 库:

Line #    Mem usage    Increment   Line Contents
================================================
    77                             @profile 
    78     7.953 MB     0.000 MB   def test_import_all():
    79    26.734 MB    18.781 MB    import Quartz.CoreGraphics as CG

它以将近 19MB 的大小拉入整个库。

试图只提取我需要的东西会得到相同的 19MB 结果:

Line #    Mem usage    Increment   Line Contents
================================================
    82                             @profile
    83     7.941 MB     0.000 MB   def test_import_some():
    84    26.727 MB    18.785 MB    from Quartz.CoreGraphics import CGImageGetWidth 

因此,似乎特定的导入与实际加载的内容无关。

只需要一个巨大模块中的一小部分功能似乎是一个常见的用例。有没有办法将我需要的模块从模块加载到内存中,或者这只是使用外部库的结果?

4

2 回答 2

5

这就是模块加载的工作原理。运行时维护一组加载的模块,因此即使您只导入了几个符号,也可以访问整个模块。这有两个理想的后果:

  • 相同模块的未来导入速度很快。
  • 任何具有副作用的模块级代码都只执行一次(除非重新加载模块),而不是执行可变次数,具体取决于模块的哪些位在哪些位置导入。

如果您认为模块中的任何函数都可以访问模块名称空间,这也是相当不可避免的,无论是直接使用其中的名称还是间接通过globals(), sys.modules[__name__],eval或其他方式。因此,除非进行一些巧妙的优化来证明特定函数不会这样做(Python 实现通常不会打扰),否则整个模块命名空间必须在内存中。

于 2013-09-16T19:42:57.217 回答
0

不,没有,因为即使您认为您只需要一个函数,该函数也可能需要模块中的其他函数(或类等)。模块是可以通过导入加载的最小代码单元。如果模块可以分成多个独立的部分,并且足够大以至于会对性能产生影响,那么它应该是。否则,您不能只导入部分和/或是否可以导入也没关系。

于 2013-09-16T19:46:37.153 回答