昨天同事在部門分享中談到了Android的虛擬機(jī)機(jī)制。正好想到我在學(xué)習(xí).Net CLR的時(shí)候研究過CLR運(yùn)行時(shí)的相互關(guān)系,所以拿出來分享一下。
我們在本文中要搞清楚類型调鲸,對象,線程棧挽荡,托管堆的關(guān)系藐石。
首先你需要對內(nèi)存管理、.net框架和.net clr有個(gè)基本的了解定拟。.net框架
線程棧
我們先來看看一個(gè)加載了CLR的Microsoft Windows的進(jìn)程于微。一個(gè)進(jìn)程可能會(huì)有多個(gè)線程。一個(gè)線程創(chuàng)建時(shí)青自,會(huì)分配到1MB大小的棧角雷。
作用
- 保存向方法傳遞的實(shí)參
- 保存方法內(nèi)部定義的局部變量
棧是高位向低位地址構(gòu)建的
一個(gè)線程的棧,準(zhǔn)備調(diào)用M1方法
分配局部變量name的內(nèi)存
M1調(diào)用M2方法性穿,把實(shí)參s壓入棧,調(diào)用方法時(shí)雷滚,還需要將“返回地址”壓入棧需曾,被調(diào)用方法結(jié)束后,返回這個(gè)位置祈远。
M2開始執(zhí)行呆万,最終到達(dá)return語句,指令指針被設(shè)置為棧中的返回地址车份,M2的棧幀(指當(dāng)前線程中調(diào)用棧的一個(gè)方法調(diào)用谋减,每個(gè)方法調(diào)用都會(huì)在調(diào)用棧中創(chuàng)建并壓入一個(gè)棧幀)會(huì)被釋放。線程棧如下圖
線程將繼續(xù)執(zhí)行M1在調(diào)用M2之后的代碼
托管堆
我們假定有這兩個(gè)類的定義
window進(jìn)程已經(jīng)啟動(dòng)扫沼,托管堆已初始化出爹,已經(jīng)創(chuàng)建了一個(gè)線程庄吼。該線程已經(jīng)調(diào)用了一些代碼,現(xiàn)在馬上要調(diào)用M3严就。
這時(shí)候CLR要做的事情
- 確保M3內(nèi)部引用的所有類型的程序集都已加載
- 利用程序集的元數(shù)據(jù)創(chuàng)建類型對象(Type Object表示類型本身)
類型對象包括
- 類型對象指針(Type Object Pointer)和同步塊索引(sync block index)
- 靜態(tài)字段
- 方法表
當(dāng)前面的事情做好后总寻,開始執(zhí)行M3的本地代碼,首先為局部變量分配內(nèi)存梢为,CLR會(huì)自動(dòng)將局部變量初始化成null或0
接下來渐行,M3代碼開始構(gòu)造一個(gè)Manager實(shí)例(也就是一個(gè)Manager對象),步驟如下
- 初始化類型對象指針铸董,并指向與對象對應(yīng)的類型對象
- 初始化同步索引塊
- 將所有實(shí)例字段初始化
- new操作符會(huì)返回對象的內(nèi)存地址祟印,將之保存到變量e
對象包括
- 類型對象指針(Type Object Pointer)和同步塊索引(sync block index)
-
實(shí)例字段
image.png
M3下一行調(diào)用Employee的靜態(tài)方法Lookup。調(diào)用靜態(tài)方法的步驟
- CLR會(huì)定位與定義靜態(tài)方法的類型相對應(yīng)的類型對象
- JIT編譯器在類型對象的方法表找到該方法粟害,對方法進(jìn)行JIT進(jìn)行編譯(如果需要的話)蕴忆,再調(diào)用JIT編譯的代碼
- Lookup方法在堆上構(gòu)造一個(gè)新的Manager對象,并返回地址
- M3將地址存到變量e
需要注意的是我磁,變量e已經(jīng)引用了新的對象孽文。原來的對象沒有變量引用,GC將會(huì)對其自動(dòng)進(jìn)行回收夺艰。
M3的下一行代碼調(diào)用虛實(shí)例方法GenProgressReport芋哭。調(diào)用一個(gè)虛實(shí)例方法時(shí),JIT編譯器要在方法中生成一些額外的代碼郁副;方法每次調(diào)用時(shí)减牺,都會(huì)調(diào)用這些代碼。
- 檢查發(fā)出調(diào)用的變量存谎,跟隨地址來到發(fā)出調(diào)用的對象拔疚,檢查對象的類型對象指針,找到類型對象既荚,并在方法表中定位該方法稚失。(和非虛方法的區(qū)別:非虛關(guān)心的是變量e的類型,而虛關(guān)心的是變量e所指向的對象的類型)
- JIT編譯器在類型對象的方法表找到該方法恰聘,對方法進(jìn)行JIT進(jìn)行編譯(如果需要的話)句各,再調(diào)用JIT編譯的代碼
Manager和Employee類型對象也有類型對象指針,那這些指針是指向哪里的呢晴叨?實(shí)際上凿宾,CLR在進(jìn)程運(yùn)行時(shí),會(huì)為System.Type創(chuàng)建一個(gè)特殊的類型對象兼蕊,Manager和Employee的類型對象的類型對象指針都指向它初厚。System.Type的類型對象指針就指向自身。
System.Obejct有一個(gè)GetType方法孙技,返回類型對象指針产禾,這樣就可以判斷系統(tǒng)中任何對象(也包括類型對象)的類型了排作。