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/)