您好,登錄后才能下訂單哦!
python虛擬機運行的原理是什么?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
一、過程概述
1、python先把代碼(.py文件)編譯成字節碼,交給字節碼虛擬機,然后虛擬機會從編譯得到的PyCodeObject對象中一條一條執行字節碼指令,并在當前的上下文環境中執行這條字節碼指令,從而完成程序的執行。Python虛擬機實際上是在模擬操作中執行文件的過程。PyCodeObject對象中包含了字節碼指令以及程序的所有靜態信息,但沒有包含程序運行時的動態信息——執行環境(PyFrameObject)
2、字節碼在python虛擬機程序里對應的是PyCodeObject對象;.pyc文件是字節碼在磁盤上的表現形式。
3、從整體上看:OS中執行程序離不開兩個概念:進程和線程。python中模擬了這兩個概念,模擬進程和線程的分別是PyInterpreterState和PyTreadState。即:每個PyThreadState都對應著一個幀棧,python虛擬機在多個線程上切換。當python虛擬機開始執行時,它會先進行一些初始化操作,最后進入PyEval_EvalFramEx函數,它的作用是不斷讀取編譯好的字節碼,并一條一條執行,類似CPU執行指令的過程。函數內部主要是一個switch結構,根據字節碼的不同執行不同的代碼。
二、關于.pyc文件
PyCodeObject對象的創建時機是模塊加載的時候,即import。
1、執行 python test.py 會對test.py進行編譯成字節碼并解釋執行,但不會生成test.pyc
2、如果test.py中加載了其他模塊,如import urllib2,那么python會對urllib2.py進行編譯成字節碼,生成urllib2.pyc,然后對字節碼解釋執行。
3、如果想生成test.pyc,我們可以使用python內置模塊py_compile來編譯。
也可以執行命令 python -m test.py 這樣,就生成了test.pyc
4、加載模塊時,如果同時存在.py和.pyc,python會使用.pyc運行,如果.pyc的編譯時間早于.py的時間,則重新編譯.py,并更新.pyc文件。
三、關于PyCodeObject
Python代碼的編譯結果就是PyCodeObject對象,如下:
typedef struct { PyObject_HEAD int co_argcount; /* 位置參數個數 */ int co_nlocals; /* 局部變量個數 */ int co_stacksize; /* 棧大小 */ int co_flags; PyObject *co_code; /* 字節碼指令序列 */ PyObject *co_consts; /* 所有常量集合 */ PyObject *co_names; /* 所有符號名稱集合 */ PyObject *co_varnames; /* 局部變量名稱集合 */ PyObject *co_freevars; /* 閉包用的變量名集合 */ PyObject *co_cellvars; /* 內部嵌套函數引用的變量名集合 */ /* The rest doesn’t count for hash/cmp */ PyObject *co_filename; /* 代碼所在文件名 */ PyObject *co_name; /* 模塊名|函數名|類名 */ int co_firstlineno; /* 代碼塊在文件中的起始行號 */ PyObject *co_lnotab; /* 字節碼指令和行號的對應關系 */ void *co_zombieframe; /* for optimization only (see frameobject.c) */ } PyCodeObject;
四、執行字節碼
Python虛擬機的原理就是模擬可執行程序再X86機器上的運行
假如test.py用C語言來實現,會是下面這個樣子:
const char *s = “hello”; void func() { printf(“%s\n”, s); } int main() { func(); return 0; }
Python虛擬機的原理就是模擬上述行為。當發生函數調用時,創建新的棧幀,對應Python的實現就是PyFrameObject對象。
PyFrameObject對象創建程序運行時的動態信息,即執行環境,相關源碼大致如下:
typedef struct _frame{ PyObject_VAR_HEAD //"運行時棧"的大小是不確定的 struct _frame *f_back; //執行環境鏈上的前一個frame,很多個PyFrameObject連接起來形成執行環境鏈表 PyCodeObject *f_code; //PyCodeObject 對象,這個frame就是這個PyCodeObject對象的上下文環境 PyObject *f_builtins; //builtin名字空間 PyObject *f_globals; //global名字空間 PyObject *f_locals; //local名字空間 PyObject **f_valuestack; //"運行時棧"的棧底位置 PyObject **f_stacktop; //"運行時棧"的棧頂位置 //... int f_lasti; //上一條字節碼指令在f_code中的偏移位置 int f_lineno; //當前字節碼對應的源代碼行 //... //動態內存,維護(局部變量+cell對象集合+free對象集合+運行時棧)所需要的空間 PyObject *f_localsplus[1]; } PyFrameObject;
每一個 PyFrameObject對象都維護了一個 PyCodeObject對象,這表明每一個 PyFrameObject中的動態內存空間對象都和源代碼中的一段Code相對應。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。