Python内存管理指南

  • 2019 年 11 月 27 日
  • 筆記

原标题 | Memory Management in Python

作 者 | Jun Wu

翻 译 | 天字一号

审 校 | 唐里、Pita

对于软件开发人员而言,了解内存管理很重要。随着Python在软件开发中得到广泛使用,编写高效的Python代码通常意味着需要编写内存高效使用的代码。随着大数据的使用越来越广泛,内存管理的重要性不容忽视。无效的内存管理会导致应用程序和服务器端组件运行缓慢。内存泄漏通常会导致花费大量时间进行测试和调试,它还会严重破坏数据处理并引起并发处理问题。

即使大多数Python的内存管理都是由Python内存管理器完成的,但了解最佳编码实践以及Python的内存管理器的工作方式仍可以使代码更高效和可维护。

对于软件开发人员而言,内存管理最重要的部分是内存分配。了解在计算机的物理或虚拟内存中分配空白空间的过程至关重要。有两种类型的内存分配。

静态内存分配 – 程序在编译时分配了内存。例如在C / C ++中,您只能声明具有固定大小的静态数组。在编译时分配内存。堆栈用于实现静态分配。在这种情况下,不能重用内存。

static int a=10;

动态内存分配 – 在运行时为程序分配了内存。例如,在C / C ++中,您可以使用一元运算符new声明数组。内存在运行时分配。堆用于实现动态分配。在这种情况下,不需要时可以释放和重用内存。

int *p;  p=new int;

关于Python的好处是Python中的所有东西都是对象。这意味着动态内存分配是Python内存管理的基础。当不再需要对象时,Python内存管理器将自动从它们中回收内存。

Python是使用C编程语言实现的高级编程语言。Python内存管理器管理Python的内存分配。有一个私有heap,其中包含所有Python对象和数据结构。Python内存管理器按需管理Python堆。Python内存管理器具有特定于对象的分配器,可为int,string等特定对象分别分配内存。在此之下,原始内存分配器与操作系统的内存管理器进行交互,以确保私有堆上有空间。

Python内存管理器管理称为“块”的内存块。相同大小的块的集合构成了“池”。池是在Arenas上创建的,在堆= 64池上分配了256kB的内存块。如果对象被销毁,则内存管理器将用相同大小的新对象填充此空间。

方法和变量在堆栈存储器中创建。每当创建方法和变量时,都会创建一个堆栈框架。只要返回方法,这些框架就会自动销毁。

堆内存中创建对象和实例变量。一旦返回变量和函数,将对垃圾对象进行垃圾回收。

请务必注意,Python内存管理器不一定会将内存释放回操作系统,而是将内存返回给python解释器。Python有一个小的对象分配器,用于分配内存以供进一步使用。在长时间运行的进程中,您可能有未使用内存的增量保留。

使用联接将项目添加到列表是高效Python代码的最佳做法

无需将line1,line2分别添加到mymsg,而是使用list和join。

不要这样:

mymsg=’line1n’  mymsg+=’line2n’

最好这样:

mymsg=[‘line1’,’line2']  ‘n’.join(mymsg)

避免对字符串使用+运算

如果可以避免,请不要使用+运算符进行串联。由于字符串是不可变的,因此每次将元素添加到字符串时,Python都会创建一个新的字符串和一个新的地址。这意味着每次更改字符串时都需要分配新的内存。

不要这样做:

msg=’hello’+mymsg+’world’

更好的选择:

msg=’hello %s world’ % mymsg

使用Generators

生成器允许您创建一个函数,一次返回一个项目,而不是一次返回所有项目。这意味着,如果您有大型数据集,则不必等待整个数据集都可以访问。

def __iter__(self):       return self._generator()    def _generator(self):       for itm in self.items():           yield itm

将评估置于循环之外

如果要遍历数据,则可以使用正则表达式的缓存版本。

match_regex=re.compile(“foo|bar”)    for i in big_it:       m = match_regex.search(i)           ….

将函数分配给局部变量

Python访问局部变量要比全局变量有效得多。将函数分配给局部变量,然后使用它们。

myLocalFunc=myObj.func  for i in range(n):      myLocalFunc(i)

使用内置函数和库

尽可能使用内置函数和库。内置函数通常使用最佳内存使用方法来实现。

不要这样做:

mylist=map(str.lower, oldlist)

与循环相比,使用关键字参数创建数据集的更好选择:

mycounter = Counter (a = 1, b = 2, c = 3, d = 5, e = 6, f = 7, g = 8)  for i in mycounter.elements()

通过使用itertools摆脱不必要的循环

itertools(https://docs.python.org/3/library/itertools.html)为您节省了大量的循环时间。它还摆脱了代码的复杂性。

不要这样做:

mylist=[]  for shape in [True, False]:       for weight in (1, 5):            firstlist=firstlist+function(shape, weight)

最好这样:

from itertools import product, chain  list(chain.from_iterable(function(shape, weight) for weight, shape in product([True, False], range(1, 5))))

覆盖_new_并利用元类来进行安全和内存管理——作者@maxwell flitton

重写_new_并利用元类进行安全和内存管理,方法是@maxwell flitton 在执行Singleton和Flyweight模式时,重写__new__并利用元类对内存管理也非常有用和安全。例如,这是一个读取Yaml文件的dict对象的示例。因为它的元类一经定义便是单例设计模式,因此可以将其导入系统中的任何位置并再次定义,并且解释器将仅指向初始对象。它减少了内存占用并确保了安全性。不管团队中的其他开发人员多么初级,它们都不会导致重复的对象,从而防止它们更改系统某一部分中的命令,并防止另一部分中引用另一条命令。

class Singleton(type):  _instances = {}   def __call__(cls, *args, **kwargs):   if cls not in cls._instances:   cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)   return cls._instances[cls]    class ConfigDict(dict, metaclass=Singleton):   def __init__(self):   super().__init__(self.read_config_file())     @staticmethod   def read_config_file():   “””   Reads config file based on path passed when running app.     :return: (dict) loaded data from yml file   “””   config_file_path = sys.argv[-1]   if not config_file_path.endswith(“.yml”):   raise ConfigDictError(message=”yml file not passed into flask app but {} instead”.format(config_file_path))   return yaml.load(open(str(config_file_path)), Loader=yaml.FullLoader)

如何检查Python代码的性能

您可以使用配置文件模块(例如cProfile和Profile:https://docs.python.org/3/library/profile.html)进行性能检查。

python -m cProfile [-o output_file][-s sort_order](-m module | myscript.py)

阅读有关Python内存管理的更多信息,可查看以下资源:

  • 流利的Python:清晰,简洁,有效的编程(http://geni.us/xA2PP)
  • Python Cookbook:精通Python 3(http://geni.us/yAoO1S)
  • 真正的Python:Python中的内存管理(https://realpython.com/python-memory-management/)
  • Python.org内存管理(https://docs.python.org/3/c-api/memory.html)
  • Atem Golubin:Python中的内存管理(https://rushter.com/blog/python-memory-managment/)