第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Python 進(jìn)階應(yīng)用教程

Python 進(jìn)階應(yīng)用教程
01 Python 的對象和類 02 Python 類屬性和實(shí)例屬性 03 Python類的構(gòu)造方法、析構(gòu)方法、實(shí)例方法 04 Python 類的私有屬性和私有方法 05 Python 類的繼承和多繼承 06 Python 類實(shí)戰(zhàn) 07 Python 中的迭代器實(shí)現(xiàn)原理 08 Python 中的迭代器趣味實(shí)踐 09 Python 中的生成器實(shí)現(xiàn)原理 10 Python 中的生成器趣味實(shí)踐 11 Python 中的錯誤和異常 12 Python 中的異常處理 13 Python 中的模塊 14 Python 標(biāo)準(zhǔn)庫之 os 模塊 15 Python 標(biāo)準(zhǔn)庫之 sys 模塊 16 Python 標(biāo)準(zhǔn)庫之 math 模塊 17 Python 標(biāo)準(zhǔn)庫之 random 模塊 18 Python 標(biāo)準(zhǔn)庫之 Json 模塊 19 Python 標(biāo)準(zhǔn)庫 datetime 模塊 20 Python 中的常用第三方模塊 21 Python 中的命名空間 22 Python 中的作用域 23 Python 中的文件 IO 操作 24 Python 基礎(chǔ)實(shí)戰(zhàn) 25 Python 內(nèi)置函數(shù) 26 Python 中使用正則表達(dá)式 27 使用 Python 操作 MySQL 數(shù)據(jù)庫 28 使用 Python 操作 Mongo 數(shù)據(jù)庫 29 使用 Python 操作 Redis 數(shù)據(jù)庫 30 使用 Python 發(fā)送一封郵件 31 threading 之 Thread 的使用 32 threading 之 Lock 的基本使用 33 Python 生產(chǎn)者消費(fèi)者模型 34 Python 的內(nèi)存管理與垃圾回收 35 Python 領(lǐng)域運(yùn)用:網(wǎng)絡(luò)爬蟲 36 Python 領(lǐng)域運(yùn)用:Web 開發(fā) 37 Python 領(lǐng)域運(yùn)用:自動化運(yùn)維 38 Python 領(lǐng)域運(yùn)用:自動化測試

Python 的內(nèi)存管理與垃圾回收

1. 內(nèi)存管理概述

1.1 手動內(nèi)存管理

在計(jì)算機(jī)發(fā)展的早期,編程語言提供了手動內(nèi)存管理的機(jī)制,例如 C 語言,提供了用于分配和釋放的函數(shù) malloc 和 free,如下所示:

#include <stdlib.h>

void *malloc(size_t size);
void free(void *p);
  • 函數(shù) malloc 分配指定大小 size 的內(nèi)存,返回內(nèi)存的首地址
  • 函數(shù) free 釋放之前申請的內(nèi)存

程序員負(fù)責(zé)保證內(nèi)存管理的正確性:使用 malloc 申請一塊內(nèi)存后,如果不再使用,需要使用 free 將其釋放,示例如下:

#include <stdlib.h>

void test()
{
    void *p = malloc(10);

    訪問 p 指向的內(nèi)存區(qū)域;

    free(p);
}

int main()
{
    test();
}
  • 使用 malloc(10) 分配一塊大小為 10 個字節(jié)的內(nèi)存區(qū)域
  • 使用 free§ 釋放這塊內(nèi)存區(qū)域

如果忘記釋放之前使用 malloc 申請的內(nèi)存,則會導(dǎo)致可用內(nèi)存不斷減少,這種現(xiàn)象被稱為 “內(nèi)存泄漏”,示例如下:

#include <stdio.h>
#include <stdlib.h>

void test()
{
    void *p = malloc(10);

    訪問 p 指向的內(nèi)存區(qū)域;
}

int main()
{
    while (1)
        test();
}
  • 在函數(shù) test 中,使用 malloc 申請一塊內(nèi)存
    • 但是使用完畢后,忘記釋放了這塊內(nèi)存
  • 在函數(shù) main 中,循環(huán)調(diào)用函數(shù) test()
    • 每次調(diào)用函數(shù) test(),都會造成內(nèi)存泄漏
    • 最終,會耗盡所有的內(nèi)存

1.2 自動內(nèi)存管理

在計(jì)算機(jī)發(fā)展的早期,硬件性能很差,為了最大程度的壓榨硬件性能,編程語言提供了手動管理內(nèi)存的機(jī)制。手動管理內(nèi)存的機(jī)制的優(yōu)點(diǎn)在于能夠有效規(guī)劃和利用內(nèi)存,其缺點(diǎn)在于太繁瑣了,很容易出錯。

隨著計(jì)算機(jī)的發(fā)展,硬件性能不斷提高,這時候出現(xiàn)的編程語言,例如:Java、C#、PHP、Python,則提供了自動管理內(nèi)存的機(jī)制:程序員申請內(nèi)存后,不需要再顯式的釋放內(nèi)存,由編程語言的解釋器負(fù)責(zé)釋放內(nèi)存,從根本上杜絕了 “內(nèi)存泄漏” 這類錯誤。

在下面的 Python 程序中,在無限循環(huán)中不斷的申請內(nèi)存:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

while True:
    person = Person('tom', 13)
  • 類 Person 包含兩個屬性:name 和 age
  • 在 while 循環(huán)中,使用類 Person 生成一個實(shí)例 person
    • 需要申請一塊內(nèi)存用于保存實(shí)例 person 的屬性

Python 解釋器運(yùn)行這個程序時,發(fā)現(xiàn)實(shí)例 person 不再被引用后,會自動的釋放 person 占用的空間。因此這個程序可以永遠(yuǎn)的運(yùn)行下去,而不會把內(nèi)存耗盡。

2. 基于引用計(jì)數(shù)的內(nèi)存管理

2.1 基本原理

引用計(jì)數(shù)是一種最簡單的自動內(nèi)存管理機(jī)制:

  • 每個對象都有一個引用計(jì)數(shù)
  • 當(dāng)把該對象賦值給一個變量時,對象的引用計(jì)數(shù)遞增 1

引用計(jì)數(shù)的實(shí)例如下:

A = object()
B = A
A = None
B = None
  • 在第 1 行,使用 object() 創(chuàng)建一個對象,變量 A 指向該對象
    • 對象的引用計(jì)數(shù)變化為 1
  • 在第 2 行,變量 B 指向相同的對象
    • 對象的引用計(jì)數(shù)變化為 2
  • 在第 3 行,變量 A 指向 None
    • 對象的引用計(jì)數(shù)變化為 1
  • 在第 3 行,變量 B 指向 None
    • 對象的引用計(jì)數(shù)變化為 0

引用計(jì)數(shù)

從圖中可以看出,當(dāng)變量 A 和變量 B 都不再指向?qū)ο髸r,對象的引用計(jì)數(shù)變?yōu)?0,系統(tǒng)檢測到該對象成為廢棄對象,可以將此廢棄對象回收。

2.2 優(yōu)點(diǎn)和缺點(diǎn)

引用計(jì)數(shù)的優(yōu)點(diǎn)在于:

  • 實(shí)現(xiàn)簡單
  • 系統(tǒng)檢測到對象的引用計(jì)數(shù)變?yōu)?0 后,可以及時的釋放廢棄的對象
  • 處理回收內(nèi)存的時間分?jǐn)偟搅似綍r

引用計(jì)數(shù)的缺點(diǎn)在于:

  • 維護(hù)引用計(jì)數(shù)消耗性能,每次變量賦值時,都需要維護(hù)維護(hù)引用計(jì)數(shù)
  • 無法釋放存在循環(huán)引用的對象

下面是一個存在循環(huán)引用的例子:

class Node:
    def __init__(self, data, next):
        self.data = data
        self.next = next

node = Node(123, None)
node.next = node
node = None
  • 在第 6 行,創(chuàng)建對象 node
    • 對象 node 的 next 指向 None
    • 此時對象 node 的引用計(jì)數(shù)為 1
  • 在第 7 行,對象 node 的 next 指向 node 自身
    • 此時對象 node 的引用計(jì)數(shù)為 2
  • 在第 7 行,對象 node 指向 None
    • 此時對象 node 的引用計(jì)數(shù)為 1

對象 node 的 next 字段指向自身,導(dǎo)致:即使沒有外部的變量指向?qū)ο?node,對象 node 的引用計(jì)數(shù)也不會變?yōu)?0,因此對象 node 就永遠(yuǎn)不會被釋放了。

3. 基于垃圾回收的內(nèi)存管理

3.1 基本原理

垃圾回收是目前主流的內(nèi)存管理機(jī)制:

  • 通過一系列的稱為 “GC Root” 的對象作為起始對象
  • 從 GC Root 出發(fā),進(jìn)行遍歷
  • 最終將對象劃分為兩類:
    • 從 GC Root 可以到達(dá)的對象
    • 從 GC Root 無法到達(dá)的對象

從 GC Root 無法到達(dá)的對象被認(rèn)為是廢棄對象,可以被系統(tǒng)回收。

垃圾回收

  • 在 Python 語言中,可作為 GC Roots 的對象主要是指全局變量指向的對象。
  • 從 GC Roots 出發(fā),可以到達(dá) object 1、object 2、object 3、object 4
  • 從 GC Roots 出發(fā),無法到達(dá) object 5、object 6、object 7,它們被判定為可回收的對象

3.2 優(yōu)點(diǎn)和缺點(diǎn)

垃圾回收的優(yōu)點(diǎn)在于:

  • 可以處理存在循環(huán)引用的對象

垃圾回收的缺點(diǎn)在于:

  • 實(shí)現(xiàn)復(fù)雜
  • 進(jìn)行垃圾回收時,需要掃描程序中所有的對象,因此需要暫停程序的運(yùn)行。當(dāng)程序中對象數(shù)量較多時,暫停程序的運(yùn)行時間過長,系統(tǒng)會有明顯的卡頓現(xiàn)象。

4. Python 的內(nèi)存管理機(jī)制

Python 的內(nèi)存管理采用了混合的方法:

  • Python 使用引用計(jì)數(shù)來保持追蹤內(nèi)存中的對象,當(dāng)對象的引用計(jì)數(shù)為 0 時,回收該對象
  • Python 同時使用垃圾回收機(jī)制來回收存在有循環(huán)引用的對象

下面的例子中,演示了 Python 的內(nèi)存管理策略:

class Circular:
    def __init__(self):
        self.data = 0
        self.next = self

class NonCircular:
    def __init__(self):
        self.data = 0
        self.next = None

def hybrid():
    while True:
        circular = Circular()
        nonCircular = NonCircular()

hybrid()
  • 類 Circular,創(chuàng)建了一個包含循環(huán)引用的對象
    • self.next 指向自身,導(dǎo)致了循環(huán)引用
    • 類 Circular 的實(shí)例只能被垃圾回收機(jī)制釋放
  • 類 NonCircular,創(chuàng)建了一個不包含循環(huán)引用的對象
    • self.next 指向 None,沒有循環(huán)引用
    • 類 NonCircular 的實(shí)例可以引用計(jì)數(shù)機(jī)制釋放
  • 在方法 hybrid 中
    • 在無限循環(huán)中,不斷的申請 Circular 實(shí)例和 NonCircular 實(shí)例

通過引用計(jì)數(shù)和垃圾回收機(jī)制,內(nèi)存不會被耗盡,程序可以永遠(yuǎn)的運(yùn)行下去。