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