關于Python:9. 深入理解Python運行機制

一、Python內存管理(引用計數、垃圾回收)

Python(CPython)采用的是:

“引用計數為主,垃圾回收為輔” 的內存管理機制。

也就是說:

  • 引用計數機制:負責大部分內存釋放,簡單、高效。

  • 垃圾回收機制(GC):處理循環引用等引用計數解決不了的問題。

1. 引用計數(Reference Counting)

每個 Python 對象都有一個“引用計數”,表示當前有多少個地方在使用它。

一旦引用計數為 0,Python 立刻銷毀對象、釋放內存。

舉例說明:

a = [1, 2, 3]  # 創建列表對象,引用計數 = 1
b = a          # b 也指向這個列表,對象引用計數 = 2
del a          # 刪除 a,引用計數 = 1
del b          # 刪除 b,引用計數 = 0,對象被銷毀

可以使用 sys.getrefcount() 查看一個對象的引用計數:

import sys
x = [1, 2, 3]
print(sys.getrefcount(x))  # 注意:結果比你預期的多1,因為參數x也算一次引用

引用計數的優點:

  • 實時釋放內存:對象不用的時候,立刻回收。

  • 實現簡單:不需要像 Java 那樣復雜的 GC 跑一遍遍。

2. 引用計數的缺陷:循環引用

如果兩個對象互相引用對方,即使外部沒有引用了,引用計數也不會為0,內存就不會釋放,導致 內存泄露

示例:

class Node:def __init__(self):self.ref = Nonea = Node()
b = Node()
a.ref = b
b.ref = adel a
del b# a和b雖然沒有外部引用,但它們互相引用,所以內存不會釋放!

在這個例子中:

對象誰引用了它?引用計數
amain作用域、b.ref2
bmain作用域、a.ref2

現在執行 del adel b

對象誰引用了它?引用計數
a只剩 b.ref1
b只剩 a.ref1

引用計數永遠不會變為 0!

3. 垃圾回收(Garbage Collection,GC)

為了解決循環引用的問題,Python 內部設計了一個 GC模塊 來“定期清理”不再使用的內存。

這個 GC 是通過 “分代回收(Generational GC)” 實現的。

分代回收模型(Generational GC)

Python 把所有的對象分成 3 代:

代數含義特點
第0代新建對象最頻繁回收
第1代經常存活下來的對象偶爾回收
第2代長期存在的對象很少回收,數量最多

GC 機制假設:

“活得越久的對象,越有可能繼續活著”,所以越老的代回收越少。

回收的流程

  • Python 會監控“分配了多少個對象”和“刪除了多少個對象”。

  • 當分配/刪除數量超過閾值,就觸發 GC:

    • 先回收第0代

    • 如果仍然觸發閾值,就繼續回收第1代、第2代

  • 采用標記-清除算法:標記“可達對象”,刪除“不可達對象”

GC 模塊使用示例:

import gc# 查看當前是否啟用了自動GC
print(gc.isenabled())  # True# 手動觸發一次GC
gc.collect()# 查看GC統計信息
print(gc.get_count())  # 返回 (第0代對象數量, 第1代, 第2代)

4. 小對象內存池機制

CPython 還對**小對象(小于 512 字節)**做了優化:

  • 使用內存池(稱為 pymalloc)重復利用內存塊。

  • 這樣避免頻繁向操作系統申請/釋放內存,提高性能。

這就是為什么寫 a = 10; b = 10 時,兩個變量可能指向的是同一個對象地址

5. 總結

機制原理優點缺點
引用計數每個對象維護引用計數,0即銷毀實時、高效不能處理循環引用
垃圾回收分代收集,標記清除彌補引用計數的缺陷增加一些系統開銷
小對象池內存池優化小對象提高小對象復用效率占用一些額外內存

二、Python解釋器(CPython、PyPy)

Python 解釋器就是把你寫的 .py 源碼翻譯為計算機能執行的“指令”的程序。

目前主流解釋器有多個實現:

名稱語言實現特點適用場景
CPython用 C 寫的官方標準實現,最常用默認解釋器,穩定
PyPy用 RPython 寫支持 JIT,速度更快追求性能
Jython用 Java 寫可運行在 JVM 上,調用 JavaJava 環境
IronPython.NET 實現支持 C#/VB 調用.NET 環境
MicroPythonC實現(精簡)運行在嵌入式設備單片機開發

1. CPython(最主流、最重要)

  • CPython 是 Python 的官方實現

  • 是用 C語言 寫的解釋器(Interpreter)。

  • 所有你運行 .py 的地方,默認就是 CPython。

$ python3 --version
Python 3.11.7  ← 這就是 CPython

CPython 的執行流程

Python 源碼(.py 文件)↓
詞法/語法分析↓
AST(抽象語法樹)↓
編譯成字節碼(.pyc 文件)↓
交由 CPython 的虛擬機解釋執行

這也是為什么會看到 .pyc 文件,它其實就是:

????????Python 的“中間語言”,類似 Java 的 .class 文件。

CPython 底層結構

typedef struct _object {Py_ssize_t ob_refcnt;     // 引用計數PyTypeObject *ob_type;    // 類型信息
} PyObject;

CPython(Python 的官方解釋器)就是用 C 語言編寫的

Py_ssize_t ob_refcnt;       // 當前對象的引用計數,決定是否自動釋放
PyTypeObject *ob_type;      // 指向該對象的類型結構體,比如 int、str 類型

每個 Python 中的對象(int、list、dict 等)在底層都是一個 PyObject 結構體,通過這個結構可以知道:

  • 它被引用了多少次(用于自動內存管理)

  • 它到底是什么類型(用于運行時類型識別)

CPython 的缺陷:GIL(全局解釋器鎖)

CPython 使用 GIL 來確保多線程安全:

Global Interpreter Lock→ 同一時間,只允許一個線程執行 Python 字節碼

這意味著 Python 的多線程并不能真正并發運行計算密集型任務。CPU 利用率低。

2. PyPy(性能極致的解釋器)

  • PyPy 是用一種叫 RPython(可靜態類型的Python子集) 實現的 Python 解釋器。

  • 最大亮點是 JIT(Just-In-Time)編譯技術,可以把熱代碼編譯成機器碼,加速運行。

PyPy 的優勢

特性說明
?JIT 編譯PyPy 會將頻繁執行的代碼“編譯為機器碼”加速運行
?智能優化內聯、移除多余變量等操作自動完成
? 性能提升實測一般比 CPython 快 4~10 倍

例如:

from time import timedef f():s = 0for i in range(10_000_000):s += ireturn sstart = time()
f()
print("耗時:", time() - start)

同樣的代碼,用 PyPy 跑會明顯快很多。

如何下載安裝 PyPy:

1)訪問官網下載頁面:https://www.pypy.org/download.html

2)解壓縮到一個目錄,比如:C:\pypy3.9

3)打開命令行,輸入:

C:\pypy3.9\pypy3.exe

如果是 Linux / Mac 用戶:

sudo apt install pypy3       # Ubuntu
# 或
brew install pypy3           # Mac(需安裝 Homebrew)

4)運行代碼用 PyPy 解釋器

比如:

pypy3 your_script.py

或者:

pypy3
>>> print("hello from PyPy!")

這樣就不再用默認的 CPython 。


三、編譯原理初步(AST抽象語法樹、字節碼)

Python 作為一種 解釋型語言,它的代碼執行過程包括了“編譯”和“解釋”兩個階段:

編譯階段:把 Python 源代碼編譯成一種中間表示形式(字節碼),這個字節碼并不是直接機器碼,而是 Python 虛擬機能理解的低級指令。

解釋執行階段:字節碼由 Python 解釋器(虛擬機)執行。

這兩個過程中的重要組成部分就是 AST(抽象語法樹) 和 字節碼。

1. 什么是 AST(抽象語法樹)?

AST(抽象語法樹) 是對 Python 源代碼的一種樹狀表示,它的每個節點代表了 Python 程序中的一個結構元素(如表達式、語句等)。它比語法樹更簡潔,去除了與編程語言具體語法無關的部分。

  • AST 是 Python 編譯階段的產物。

  • Python 代碼首先通過 詞法分析(將源碼轉換為標記)和 語法分析(將標記轉換為 AST)兩步生成。

  • 在 AST 之上,Python 可以進行代碼優化、分析、轉換、生成字節碼等操作。

?AST 的重要性

  • 代碼分析與優化:通過 AST,你可以分析代碼的結構,做靜態分析(例如變量的使用、控制流等)或進行代碼優化。

  • 代碼轉換:AST 是生成字節碼的基礎,修改 AST 可以進行代碼重寫、反混淆等操作。

  • 反向工程:通過分析 AST,你可以將混淆代碼或壓縮代碼還原為易懂的原始代碼結構。

生成 AST

可以使用 Python 的 ast 模塊來分析和操作 Python 的 AST。例如,下面的代碼將 Python 代碼解析成 AST:

import astsource_code = "x = 1 + 2 * 3"
tree = ast.parse(source_code)# 打印 AST 的結構
ast.dump(tree, indent=4)

輸出會是類似這樣的結構(樹狀結構):

Module(body=[Assign(targets=[Name(id='x', ctx=Store())],value=BinOp(left=Num(n=1), op=Add(), right=BinOp(left=Num(n=2), op=Mult(), right=Num(n=3))))]
)

這就是 Python 代碼的 AST 結構。可以看到,它把算式 1 + 2 * 3 轉換成了一個樹狀結構,節點包含了操作符、操作數、表達式等。

AST 操作示例

通過操作 AST,你可以修改代碼結構,比如實現代碼重構、自動化修改等:

class MyTransformer(ast.NodeTransformer):def visit_BinOp(self, node):if isinstance(node.op, ast.Add):node.op = ast.Sub()  # 把加法變成減法return node# 修改 AST
transformer = MyTransformer()
transformed_tree = transformer.visit(tree)# 查看修改后的樹
ast.dump(transformed_tree, indent=4)

2. 什么是字節碼(Bytecode)?

字節碼 是一種中間代碼,Python 將源代碼編譯成字節碼后,由 Python 的虛擬機(PVM)解釋執行。它比源代碼更接近機器碼,但仍然獨立于平臺。

  • 字節碼的作用:通過將源碼編譯成字節碼,Python 可以實現跨平臺運行,只需要安裝 Python 解釋器,就能執行相同的字節碼。

  • .pyc 文件:字節碼通常保存在 .pyc 文件中,位于 __pycache__ 目錄下。Python 會根據文件的修改時間來決定是否重新編譯。

字節碼的生成過程

  1. 編譯:Python 源代碼通過 CPython 編譯器轉換為字節碼(.pyc 文件)。每次你運行 .py 文件時,CPython 會首先檢查是否有 .pyc 文件,如果沒有就編譯成字節碼。

  2. 執行:字節碼通過 Python 虛擬機(PVM)解釋執行。

字節碼反匯編

使用 dis 模塊,可以看到 Python 代碼的字節碼。例如:

import disdef example():a = 1 + 2return adis.dis(example)

輸出結果會顯示字節碼:

  2           0 LOAD_CONST               1 (1)2 LOAD_CONST               2 (2)4 BINARY_ADD6 STORE_NAME               0 (a)8 LOAD_NAME                0 (a)10 RETURN_VALUE

這說明:

  • 先把常量 12 加載到棧上(LOAD_CONST),

  • 執行加法(BINARY_ADD),

  • 把結果存到變量 a 中(STORE_NAME)。

字節碼與機器碼的關系

字節碼比源代碼更接近機器碼,但它仍然不是直接可以由 CPU 執行的代碼。在 CPython 中,字節碼是由 Python 解釋器逐條解釋執行的。而機器碼則是直接由硬件執行的代碼。

3. 結合 AST 和 字節碼的實際應用

應用場景:代碼重構、反混淆

在做 JS 逆向APP 逆向時,很多時候需要分析混淆代碼并重構它。在 Python 中,AST 是一個非常好的工具,可以幫助理解代碼的結構,進行重構、逆向等操作。

例子:重構混淆代碼

比如,將一段復雜的運算式改寫為更易讀的形式:

# 混淆的代碼
x = 1 + 2 * 3# 解析并重構為
x = 7

通過 AST,可以提取出原始的運算結構,并將它們轉換為更容易理解的形式。

應用場景:性能優化

在性能優化中,了解 Python 如何將源代碼轉化為字節碼,有助于優化代碼,避免不必要的計算、內存分配等操作。例如,避免頻繁的內存分配、減少不必要的對象創建,可以提高程序的性能。

術語含義作用
AST抽象語法樹,一種樹狀結構代碼結構分析、重構、靜態分析、代碼生成和優化
字節碼中間代碼,比源碼更低級,但不依賴平臺Python 跨平臺運行,虛擬機解釋執行

四、C擴展開發(如需要極限優化)

C 擴展就是使用 C 語言編寫的 Python 模塊,它可以被 Python 調用,像普通模塊一樣 import

為什么要用 C 寫 Python 模塊?

  • Python 本身是用 C 寫的(CPython)

  • Python 解釋型的性能較低,尤其在數值計算、循環密集任務中較慢

  • C 語言性能高,可以編寫性能關鍵模塊,再用 Python 調用

  • 還能直接調用操作系統或硬件資源,或者加載第三方底層庫(如 OpenSSL)

實際例子:寫一個簡單的 C 擴展模塊

創建一個 C 模塊 myfast.c,提供一個加法函數給 Python 調用。

文件結構:

myfast/
├── myfast.c
└── setup.py

1)?myfast.c 內容如下:

#include <Python.h>// C函數:兩個數相加
static PyObject* add(PyObject* self, PyObject* args) {int a, b;// 從 Python 傳入參數解析為 C 中的 intif (!PyArg_ParseTuple(args, "ii", &a, &b)) {return NULL;}// 返回一個 Python 整數return PyLong_FromLong(a + b);
}// 定義方法表
static PyMethodDef MyFastMethods[] = {{"add", add, METH_VARARGS, "Add two numbers"},{NULL, NULL, 0, NULL}
};// 定義模塊
static struct PyModuleDef myfastmodule = {PyModuleDef_HEAD_INIT,"myfast",       // 模塊名NULL,           // 文檔(可為 NULL)-1,MyFastMethods
};// 初始化模塊
PyMODINIT_FUNC PyInit_myfast(void) {return PyModule_Create(&myfastmodule);
}

2)?setup.py 構建腳本:

from setuptools import setup, Extensionmodule = Extension('myfast', sources=['myfast.c'])setup(name='myfast',version='1.0',description='A demo C extension for Python',ext_modules=[module]
)

3)編譯模塊

運行:

python setup.py build_ext --inplace

這會生成一個 .so 文件(Linux/mac)或 .pyd(Windows),然后就可以像普通模塊一樣導入:

4)Python 中使用

import myfastprint(myfast.add(3, 5))  # 輸出 8

高級應用方向

調用已有 C/C++ 庫(如 OpenSSL、libcurl)

可以封裝 C 函數為 Python 接口,甚至是使用 extern 引用已有 .so/.dll

寫“黑盒”模塊

很多商業代碼、加密算法,甚至反爬參數邏輯會被寫成 C 模塊,然后 只暴露一個接口給 Python,大大提高逆向難度。

?用于性能關鍵場景

在圖像處理、數據加密、音視頻處理、矩陣運算、機器學習中,Python 常調用 NumPy(內部也是 C 實現)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78576.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78576.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78576.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【STM32單片機】#13 RTC實時時鐘

主要參考學習資料&#xff1a; B站江協科技 STM32入門教程-2023版 細致講解 中文字幕 開發資料下載鏈接&#xff1a;https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwddspb 單片機套裝&#xff1a;STM32F103C8T6開發板單片機C6T6核心板 實驗板最小系統板套件科協 目錄 Uni…

SecureCRT 使用指南:安裝、設置與高效操作

目錄 一、SecureCRT 簡介 1.1 什么是 SecureCRT&#xff1f; 1.2 核心功能亮點 1.3 軟件特點 二、SecureCRT 安裝與激活 2.1 安裝步驟&#xff08;Windows 系統&#xff09; 2.2 激活與破解&#xff08;僅供學習參考&#xff09; 三、基礎配置與優化 3.1 界面與編碼設…

3.5/Q1,GBD數據庫最新一區文章解讀

文章題目&#xff1a;Global burden of low vision and blindness due to age-related macular degeneration from 1990 to 2021 and projections for 2050 DOI&#xff1a;10.1186/s12889-024-21047-x 中文標題&#xff1a;1990年至2021年因年齡相關性黃斑變性導致的低視力和失…

【Hive入門】Hive安全管理與權限控制:基于SQL標準的授權GRANT REVOKE深度解析

目錄 引言 1 Hive權限模型概述 2 SQL標準授權基礎 2.1 核心概念解析 2.2 授權模型工作流程 3 GRANT/REVOKE語法詳解 3.1 基礎授權語法 3.2 權限回收語法 3.3 參數說明 4 授權場景 4.1 基礎授權示例 4.2 列級權限控制 4.3 視圖權限管理 5 權限查詢與驗證 5.1 查看…

無縫監控:利用 AWS X-Ray 增強 S3 跨賬戶復制的可見性

您準備好提升您的云和 DevOps 技能了嗎? ??《云原生devops》專門為您打造,我們精心打造的 30 篇文章庫,這些文章涵蓋了 Azure、AWS 和 DevOps 方法論的眾多重要主題。無論您是希望精進專業知識的資深專業人士,還是渴望學習相關知識的新手,這套資源庫都能滿足您的需求。 …

Python Cookbook-7.2 使用 pickle 和 cPickle 模塊序列化數據

任務 你想以某種可以接受的速度序列化和重建Python 數據結構&#xff0c;這些數據既包括基本Python 對象也包括類和實例。 解決方案 如果你不想假設你的數據完全由基本 Python 對象組成&#xff0c;或者需要在不同的 Python 版本之間移植&#xff0c;再或者需要將序列化后的…

2025.5.5總結

今日感悟&#xff1a;這假期就這樣結束了&#xff0c;玩了一次滑板&#xff0c;打掃了一次租房&#xff0c;出去逛了一次街&#xff0c;看完了一本書&#xff0c;追了一部劇。既沒有家人&#xff0c;也沒有能一同暢飲的同學&#xff0c;更沒有對象&#xff0c;顯得確實有些孤獨…

MySQL | DQL語句-連接查詢

MySQL | DQL語句-連接查詢 &#x1fa84;個人博客&#xff1a;https://vite.xingji.fun 什么是連接查詢 從一張表中查詢數據稱為單表查詢。從兩張或更多張表中聯合查詢數據稱為多表查詢&#xff0c;又叫做連接查詢。什么時候需要使用連接查詢&#xff1f; 比如這樣的需求&…

Vite簡單介紹

Vite 是一個現代化的前端構建工具&#xff0c;由 Vue.js 的創始人 Evan You 開發&#xff0c;旨在提供更快的開發體驗和更高效的構建流程。它的名字來源于法語單詞“vite”&#xff0c;意為“快速”&#xff0c;這也反映了它的核心優勢——極速的冷啟動和熱模塊替換&#xff08…

C語言-回調函數

回調函數 通過函數指針調用函數&#xff0c;而這個被調用的函數稱為回調函數 回調函數是C語言中一種強大的機制&#xff0c;允許將函數作為參數傳遞給其他函數&#xff0c;從而在特定時機由后者調用。它的核心在于函數指針的使用 以下是回調函數的使用例子 先創建好一個函數…

啟發式算法-禁忌搜索算法

禁忌搜索是一種可以用于解決組合優化問題的啟發式算法&#xff0c;通過引入記憶機制跳出局部最優&#xff0c;避免重復搜索。該算法從一個初始解開始&#xff0c;通過鄰域搜索策略來尋找當前解的鄰域解&#xff0c;并在鄰域解中選擇一個最優解作為下一次迭代的當前解&#xff0…

Python 整理3種查看神經網絡結構的方法

1. 網絡結構代碼 import torch import torch.nn as nn# 定義Actor-Critic模型 class ActorCritic(nn.Module):def __init__(self, state_dim, action_dim):super(ActorCritic, self).__init__()self.actor nn.Sequential(# 全連接層&#xff0c;輸入維度為 state_dim&#xf…

Linux 查詢CPU飆高的原因

獲取進程ID ps -efgrep xxxx查詢占用最高的線程ID top -Hp 線程ID線程ID 轉 16進制數 printf 0x%x\n 線程ID基于jstack工具 跟蹤堆棧定位代碼位置 jstack 進程ID | grep 16禁止線程ID -A 20

Oracle OCP認證考試考點詳解083系列09

題記&#xff1a; 本系列主要講解Oracle OCP認證考試考點&#xff08;題目&#xff09;&#xff0c;適用于19C/21C,跟著學OCP考試必過。 41. 第41題&#xff1a; 題目 解析及答案&#xff1a; 關于應用程序容器&#xff0c;以下哪三項是正確的&#xff1f; A) 它可以包含單個…

GESP2024年3月認證C++八級( 第二部分判斷題(1-5))

孫子定理參考程序&#xff1a; #include <iostream> #include <vector> using namespace std;// 擴展歐幾里得算法&#xff1a;用于求逆元 int extendedGCD(int a, int b, int &x, int &y) {if (b 0) {x 1; y 0;return a;}int x1, y1;int gcd extende…

C 語言比較運算符:程序如何做出“判斷”?

各類資料學習下載合集 ??https://pan.quark.cn/s/8c91ccb5a474?? 在編寫程序時,我們經常需要根據不同的條件來執行不同的代碼。比如,如果一個分數大于 60 分,就判斷為及格;如果用戶的年齡小于 18 歲,就禁止訪問某個內容等等。這些“判斷”的核心,就依賴于程序能夠比…

WITH在MYSQL中的用法

WITH 子句&#xff08;也稱為公共表表達式&#xff0c;Common Table Expression&#xff0c;簡稱 CTE&#xff09;是 SQL 中一種強大的查詢構建工具&#xff0c;它可以顯著提高復雜查詢的可讀性和可維護性。 一、基本語法結構 WITH cte_name AS (SELECT ... -- 定義CTE的查詢…

多序列比對軟件MAFFT介紹

MAFFT(Multiple Alignment using Fast Fourier Transform)是一款廣泛使用且高效的多序列比對軟件,由日本京都大學的Katoh Kazutaka等人開發,最早發布于2002年,并持續迭代優化至今。 它支持從幾十條到上萬條核酸或蛋白質序列的快速比對,同時在準確率和計算效率之間提供靈…

APP 設計中的色彩心理學:如何用色彩提升用戶體驗

在數字化時代&#xff0c;APP 已成為人們日常生活中不可或缺的一部分。用戶在打開一個 APP 的瞬間&#xff0c;首先映入眼簾的便是其色彩搭配&#xff0c;而這些色彩并非只是視覺上的裝飾&#xff0c;它們蘊含著強大的心理暗示力量&#xff0c;能夠潛移默化地影響用戶的情緒、行…

Compose 中使用 WebView

在 Jetpack Compose 中&#xff0c;我們可以使用 AndroidView 組件來集成傳統的 Android WebView。以下是幾種實現方式&#xff1a; 基礎 WebView 實現 Composable fun WebViewScreen(url: String) {AndroidView(factory { context ->WebView(context).apply {// 設置布局…