日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

《python 源码剖析》 读后总结(虚拟机综述)

發布時間:2023/12/19 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《python 源码剖析》 读后总结(虚拟机综述) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我是研究過jvm 所以在讀這本書的時候總是先關注 python 的虛擬機。

關注python 的虛擬機,首先你要先了解 .py文件編譯之后,在python虛擬機中是什么的結構;換句話說,要知道pyc 二進制文件字節碼的 格式,文件魔術、字符表、字符串,常量,模塊信息、字節碼、方法和變量等信息。

然后pyc在虛擬機中執行時候,創建的對象信息是什么樣的,即pyCodeObject.如圖:


圖中的pyCodeObject包含子模塊(方法和類)和子pyCodeObject信息,這樣指針鏈接關系,構成環境鏈,環境鏈(模塊鏈)對于python虛擬機而言非常重要,是執行的關鍵!!

虛擬機是依據環境鏈需要和創建對應的pyFrameObject對象和其對應的棧結構。

然后再去了解虛擬機的架構,內存管理,垃圾回收,以及多線程的實現和一些機制。

對于虛擬機編譯py之后,在內存上創建pycodeObject,在運行的之后,同時會創建pyFrameObject對象。這個對象對應的是一個棧結構,當pycodeObject第一次使用的時候,就會被虛擬機創建運行棧數據對象,pycodeObject和pyFrameObject一一對應。pyFrameObject里面包含了pycodeObject,同時包含棧信息,執行當前環境鏈上的前一個frame信息,builtin、local、global名字空間,當前字節碼指令信息(在源代碼的行數),上一個字節碼,需要內存空間信息等。如圖:


虛擬機執行過程中,在一個環境域中(作用域)執行的結果要保存到對應的pyFrameObject中,那么才能保證在不同的作用域取值的正確性,有效性。對于pyFrameObject的調用關系(pycodeObject中import)也會在pyFrameObject中的struck_frame *last_frame? 形成棧依賴(調用)鏈。我們寫一個python文件,文件中直接聲明一個方法直接調用,python雖然也是面對對象的編程語言,但是對于開發者是可以面對過程的開發。只是虛擬機底層對函數進行了封裝,函數也是對象(python中萬物皆對象)。函數被封裝為pyFunctionObject,其中包含了參數,函數名,func_doc,func_code,func_globals,func_module等等。func_code是指向func_code對象的指針,func_code也是對象,是代碼指令對象。func_module是函數可調用的modules;func_global是函數的上下文或者函數可調用的空間。函數的調用指針指向pyFunctionObject,再轉向pyCodeObject,其中涉及參數的傳遞,上下文的使用。


對于python類與對象,類有一個統一的締造者Object 類,j基類Object類有一個type類型的metaclass,或者可以說是類對象模版。這點和python和javascript虛擬機很相似,js引擎對于方法和類都是有封裝的,都是一個對象,且在js引擎中,函數和類都分別有自己的頂層模版。對于python class 創建一個對象,首先是class對象的創建,然后根據這個class對象去創建instance 對象。class對象的創建是獲取pyTypeClassA(假如是classA類)的對象封裝,其中包含類繼承信息,class 對象在初始化的時候,調用type_new。這個方法首先做的就是獲取父類信息(python支持多繼承),然后調用metaclass模版去創建class對象。對于 對象instance的創建,虛擬機調用object_new 方法,直接獲取class對象,然后就是type_call 區執行init初始化。


對于jvm 和 python 虛擬機有很多類似的地方,雖然兩者一個是編譯型語言,一個是腳本。但是這兩者都是有源碼解析生成中間文件,中間文件在被加載后生成字節碼文件對象,然后虛擬機后面的執行都是和這個字節碼對象有關。區別在于,jvm中每一個字節碼文件就是class對象,在加載的時候就會創建類對象。而且方法是直接存儲在類對象中,不會單獨的封裝成方法對象。但是python的方法對象和類對象的管理和js引擎類似,萬物皆對象,對類和方法以及作用域都進行了對象的封裝。


對于java創建一個對象,首先到方法區的常量池中,尋找該對象的類類型,(全局常量,類的字符信息表都存在常量池中)然后檢測該類是不是已經初始化了(有沒有創建類對象),如果是就是快速創建;否則就是慢創建。

快速創建:就是直接根據類對象創建,首先在eden區,分配一塊地址,指針指向一塊空區間,設置空區間的大小(int* FirstAddress和size)。然后初始化對象頭信息,分代年齡,偏向id,偏向時間戳等。然后一些方法指針指向類對象信息,接著就是調整線程棧對象的指向,pc的調整。

慢創建:就是類沒有初始化,先將類進行加載或者初始化,然后再創建。


對于js和python對象雖然不一定和java一致,但是大致過程肯定是一樣;首先應該是符號的匹配,空間分配,初始化信息,調整引用指向。


對于php zend 虛擬機其對每一個php文件編譯生成對應的指令數組oop_array和數據數組;對于php中的類,編譯之后生成對應的數據結構,但是內部還是只是存儲的屬性變量數組指針和方法列表指針。函數列表中每一個指針指向這個方法的指令數組的首地址。對于指令執行的時候,啟動zend.execute() c代碼函數,將指令和數據指針交給函數去執行。zend_execute 調用指令的方式有CALL, SWICH和GOTO方式,call是直接的函數調用,建立函數棧幀,指令一次出入棧。goto是直接調用指令,execute.mian將指令指針直接移交給EBP指令棧頂寄存器。swich方式 是指令在兩者之間的判斷選擇。對于zend虛擬機,其內部沒有建立棧幀,只是對于對象數據和代碼指令都是存儲在分配的內存堆中。數據的存儲數據結構主要就是hashtable和數組,指令的執行是依據zend execute.main 建立的唯一的棧幀去執行。

**************************************************************************************************************

插入說一下JIT動態編譯:

靜態編譯優化和動態編譯優化最大的不同是他們在編譯時所得到的信息量的不同。靜態編譯在運行程序之前就把所有的執行代碼編譯完,這時編譯器所接受的編譯信息量是不夠多的。比如說:某個函數是否是大量地被調用了,函數的實參是不是一直是一個常數,等等。 動態編譯之于靜態編譯,缺點是它需要即時編譯代碼,但是有一個優點——編譯器可以獲得靜態編譯期所沒有的信息。比如:通過運行時的profiling可以知道哪些函數是被大量使用的。在哪些execution path上哪些函數的參數一直都沒有變,等等。不要小看這些信息,當即時編譯器了解這些信息之后可以在短時間內編譯出比靜態編譯器更優質的二進制碼。舉例來說,一般程序也遵循90-10原則,即運行時的90%里計算機是在處理其中10%的代碼,尋找到這些執行熱點代碼進行深度優化能得到比靜態編譯更好的性能(因為已知更多信息量)。? 然而現實是:即時編譯的開銷非常大,暫時還不能超越靜態編譯的總體性能。不過,一個動態語言(如JAVA,Python)有著靜態語言(如C++)所沒有的各種優勢,必然是將來程序語言發展的方向。伴隨著強大的需求,即時編譯器在將來也會更加強大。


對于解釋器語言來說(不管直接解釋 AST 還是字節碼),指令分發是個開銷很大的過程(即一個很大的 switch case ,根據得到的指令決定解釋器下一步要做什么),這樣會導致這部分的 CPU 指令緩存命中率大幅下降。


對于動態類型語言來說,JIT 時還可以做類型特化。比如一個函數 add(x, y),純解釋的話,每次執行時需要判斷 x 與 y 的類型,根據類型再做具體的操作(整數加法 / 浮點數加法 / 字符串拼接)。假使實際代碼運行過程中,x 和 y 一直都是整型類型,這些操作也不能省略,導致性能下降。但是 JIT 的時候,可以將此函數編譯成 add_int_int(x: int, y: int) 的形式,這樣性能就和編譯型語言完全相等了。


函數內聯,JIT 的時候可以根據函數調用情況,將常用的一些函數做內聯編譯。

**************************************************************************************************************

對于js虛擬機(例如 V8)它是基于JIT,沒有所謂的中間字節碼文件,在運行時的時候會針對字節碼的解析和優化處理(這樣可以獲取運行時的處理信息,以達到性能提升)。

Chakra(Microsoft Internet Explorer)
Nitro/JavaScript Core (Safari)
Carakan (Opera)
SpiderMonkey (Firefox)
V8 (Chrome, Chromium)


創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的《python 源码剖析》 读后总结(虚拟机综述)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。