pvm虛擬機基本原理


零、緒論:特別鳴謝下文博客,自己博客是對這篇博客的學習筆記:

大佬webber博客:https://www.cnblogs.com/webber1992/p/6597166.html

一、三種文件:

  1、pyc文件:py文件編譯后的二進制文件。

  2、pyo文件:優化后的py編譯的文件。

  3、pyd文件:其他語言編程的py庫。

二、python編譯的過程:

  python不單純是一種解釋性語言,也需要編譯,需要編譯成字節碼。然后模仿可執行文件的入棧出棧調用順序執行。pyc文件中保存這編譯而成的字節碼,PVM從PyCodeObject讀取字節碼一條一條執行。PyCodeObject保存字節碼以及進程上下文信息。pyc文件在import事后創建PyCodeObject對象,一般是由py_compile模塊操作的。直接執行py文件不會生成pyc,但是可以通過python -m xxx.py生成pyc文件。

從整體上看:OS中執行程序離不開兩個概念:進程和線程。python中模擬了這兩個概念,模擬進程和線程的分別是PyInterpreterStatePyTreadState。即:每個PyThreadState都對應着一個幀棧,python虛擬機在多個線程上切換。當python虛擬機開始執行時,它會先進行一些初始化操作,最后進入PyEval_EvalFramEx函數,它的作用是不斷讀取編譯好的字節碼,並一條一條執行,類似CPU執行指令的過程。函數內部主要是一個switch結構,根據字節碼的不同執行不同的代碼。

三、PyCodeObject的結構:

 1 typedef struct {
 2     PyObject_HEAD
 3     int co_argcount;        /* 位置參數個數 */
 4     int co_nlocals;         /* 局部變量個數 */
 5     int co_stacksize;       /* 棧大小 */
 6     int co_flags;   
 7     PyObject *co_code;      /* 字節碼指令序列 */
 8     PyObject *co_consts;    /* 所有常量集合 */
 9     PyObject *co_names;     /* 所有符號名稱集合 */
10     PyObject *co_varnames;  /* 局部變量名稱集合 */
11     PyObject *co_freevars;  /* 閉包用的變量名集合 */
12     PyObject *co_cellvars;  /* 內部嵌套函數引用的變量名集合 */
13     /* The rest doesn’t count for hash/cmp */
14     PyObject *co_filename;  /* 代碼所在文件名 */
15     PyObject *co_name;      /* 模塊名|函數名|類名 */
16     int co_firstlineno;     /* 代碼塊在文件中的起始行號 */
17     PyObject *co_lnotab;    /* 字節碼指令和行號的對應關系 */
18     void *co_zombieframe;   /* for optimization only (see frameobject.c) */
19 } PyCodeObject;

引用的C語言的PyCodeObject的結構體

四、執行過程:

Python虛擬機的原理就是模擬可執行程序再X86機器上的運行,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; 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM