C#運(yùn)行時(shí)相互關(guān)系淺析
本文主要講述運(yùn)行時(shí)類型、對(duì)象、線程棧和托管堆之間的相互關(guān)系,靜態(tài)方法、實(shí)例方法和虛方法的區(qū)別,以及內(nèi)存的分配和回收。
線程棧:在一個(gè)進(jìn)程中可能包含多個(gè)線程,一個(gè)線程在創(chuàng)建的時(shí)候,會(huì)分配到一個(gè)大小1MB大小的棧,棧用于存儲(chǔ)方法的實(shí)參、形參以及方法內(nèi)部的局部變量,棧是從高位內(nèi)存地址向地位地址構(gòu)建的,由于棧有先進(jìn)后出的特點(diǎn),所以先定義的變量后被回收。
下面來看一個(gè)簡單的例子,讓你更了解線程棧
由于線程棧是從高位開始分配內(nèi)存,先分配的我就畫在上面了,在調(diào)用F1();方法時(shí),分配內(nèi)存的順序是:name->n->F2的返回地址->Age->name;回收內(nèi)存的順序當(dāng)然是反過來的。在一個(gè)方法中,應(yīng)該包含一些序幕代碼,進(jìn)行一些初始化工作,還有一些尾聲代碼,等方法執(zhí)行完成之后做一些回收工作。由于方法的返回地址先分配,在方法執(zhí)行完成的時(shí)候回到返回地址,遞歸太深就容易出現(xiàn)棧溢出,請看我的《遞歸再一次讓哥震驚了》,因?yàn)閰?shù)、局部變量都必須等到方法返回的時(shí)候才能回收。
在介紹托管堆之前先看看兩個(gè)簡單的類:
publicclassPerson
{
privateintheight;
publicvoidSetHeight(intheight)
{
this.height = height;
}
publicvirtualvoidSay(stringword) { }
publicstaticstringHead()
{
return"my head";
}
publicstaticintAge = 100;
}
publicclassStudent : Person
{
publicoverridevoidSay(stringword)
{
Console.WriteLine(word);
}
}
staticvoidMain(string[] args)
{
Person student = newStudent();
student.Say("Hello cth");
student.SetHeight(172);
Person.Head();
Console.ReadLine();
}
CLR會(huì)在第一次訪問一個(gè)對(duì)象時(shí)加載該對(duì)象,在這里,定義變量student時(shí)會(huì)為Person對(duì)象在線程棧中分配內(nèi)存,第一次加載嗎,在構(gòu)造一個(gè)Student對(duì)象之前先要加載Student對(duì)象,并為Student類型對(duì)象分配內(nèi)存,并構(gòu)建一個(gè)Student對(duì)象。對(duì)象的地址存入線程棧中的局部變量student 中,我們知道類型對(duì)象的內(nèi)容包含:類型對(duì)象指針、同步索引塊、靜態(tài)字段和方法(靜態(tài)的和非靜態(tài)的),不管是類型對(duì)象、還是實(shí)例類型都必須有類型對(duì)象指針、同步索引塊;我們知道靜態(tài)字段屬于類,被這個(gè)類的所有實(shí)例共享,當(dāng)然靜態(tài)字段的內(nèi)存是在類型本身中分配的,方法也是類的所有實(shí)例共享的,他的內(nèi)存也是在類型本身中分配的,在每一個(gè)類型對(duì)象中都有一個(gè)方法表,類中定義的方法都有一個(gè)對(duì)應(yīng)的項(xiàng)。
在構(gòu)造一個(gè)對(duì)象的實(shí)例時(shí),只需要為類型對(duì)象指針、同步索引塊、該對(duì)象的實(shí)例字段分配內(nèi)存,對(duì)于對(duì)象實(shí)例來說,類型對(duì)象指針可以讓實(shí)例訪問類型對(duì)象中德靜態(tài)字段、方法等。
Student是線程棧中的定義的一個(gè)局部變量,保存Student的一個(gè)實(shí)例的在托管堆中的地址,所以他可以訪問Student對(duì)象中的字段,方法,其實(shí)訪問方法是通過類型對(duì)象指針訪問類型對(duì)象Student中的方法表中對(duì)象的項(xiàng)。
Say方法的執(zhí)行過程:變量student指向的是一個(gè)Student對(duì)象,調(diào)用的當(dāng)然是Student類型對(duì)象中的Say方法,盡管在定義student的時(shí)候是Person類型,因?yàn)樗且妙愋停赶虻氖峭泄芏阎蠸tudent對(duì)象的內(nèi)存,然后遍歷該對(duì)象的方法表,找到該方法調(diào)用。
特別說明虛方法,JIT在虛方法中加了一些額外的代碼,方法每次調(diào)用的時(shí)候都會(huì)執(zhí)行這些代碼,這些代碼會(huì)檢查發(fā)出調(diào)用的變量,然后根據(jù)這個(gè)變量找到其應(yīng)用的對(duì)象,然后調(diào)用這個(gè)對(duì)象的方法,若沒有這些代碼,你覺得CLR是調(diào)用父類的方法還是調(diào)用之類的方法呢,虛方法帶來方便的同時(shí),也多了這些必須的檢查的代碼。
SetHeight方法的執(zhí)行過程:和Say方法前面是一樣,只是在遍歷Student對(duì)象的方法表時(shí)沒有找到該方法,我們知道父類中定義的非private方法都可以被子類繼承,是因?yàn)槊總€(gè)類型都定義了一個(gè)字段引用了他的基類,如果一個(gè)類調(diào)用的方法那個(gè)方法不是自己定義的,那么編譯器會(huì)回溯類層次結(jié)構(gòu),一直到基類Object,找到相關(guān)的方法并調(diào)用,如果沒有找到相關(guān)的方法就報(bào)了異常唄。所以SetHeight方法其實(shí)調(diào)用的是Person中的SetHeight方法。
Head方法的執(zhí)行:由于Head方法是靜態(tài)方法和上面兩個(gè)方法有所不同,調(diào)用靜態(tài)方法的時(shí)候,CLR會(huì)定位與靜態(tài)方法對(duì)象的類型對(duì)象,然后在對(duì)應(yīng)實(shí)例對(duì)象對(duì)象的方法表中查找相關(guān)的記錄項(xiàng),如果沒有找到,同樣會(huì)回溯。
當(dāng)執(zhí)行完student.SetHeight(172);時(shí),student在也沒有被引用,成為垃圾,在其所在的方法返回之前將會(huì)被回收,也就是說student實(shí)例對(duì)象被回收,釋放其所在的內(nèi)存,而類型對(duì)象不會(huì)被回收,類型對(duì)象的生成周期是:對(duì)象被加載到CLR中,直到其所在的AppDomain卸載。靜態(tài)字段是他所引用類型的跟,所以被靜態(tài)類型引用的對(duì)象永遠(yuǎn)不會(huì)被回收,如果其引用的是一個(gè)集合對(duì)象,并向其中不斷的加入元素的話,就會(huì)造成內(nèi)存泄露。
以上就是關(guān)于C#運(yùn)行時(shí)相互關(guān)系的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
欄 目:C#教程
下一篇:C#中Json字符串的各種應(yīng)用類實(shí)例講解
本文標(biāo)題:C#運(yùn)行時(shí)相互關(guān)系淺析
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6896.html
您可能感興趣的文章
- 01-10時(shí)間戳與時(shí)間相互轉(zhuǎn)換(php .net精確到毫秒)
- 01-10C#中使用JSON.NET實(shí)現(xiàn)JSON、XML相互轉(zhuǎn)換
- 01-10C# 字符串string和內(nèi)存流MemoryStream及比特?cái)?shù)組byte[]之間相互轉(zhuǎn)換
- 01-10C#中圖片、二進(jìn)制與字符串的相互轉(zhuǎn)換方法
- 01-10C#實(shí)現(xiàn)XML與實(shí)體類之間相互轉(zhuǎn)換的方法(序列化與反序列化)
- 01-10C#控制臺(tái)基礎(chǔ) List泛型集合與對(duì)應(yīng)的數(shù)組相互轉(zhuǎn)換實(shí)現(xiàn)代碼
- 01-10學(xué)會(huì)使用C#異常
- 01-10C#數(shù)組中List, Dictionary的相互轉(zhuǎn)換問題
- 01-10C#實(shí)現(xiàn)char字符數(shù)組與字符串相互轉(zhuǎn)換的方法
- 01-10C#實(shí)現(xiàn)實(shí)體類和XML相互轉(zhuǎn)換


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10delphi制作wav文件的方法
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改


