1.建立一個物件
一個物件的建立過程主要分為記憶體分配和初始化兩個環節。在.NET中CLR管理的記憶體區域主要有三個部分:堆疊、GC堆、LOH堆,堆疊主要用來分配值類型資料。它的管理是有系統控制的,而不是像GC堆那樣是由GC控制的。當執行緒執行完值類型實例所在方法後,這塊空間將會被自動釋放,一般棧的執行效率高不過容量有限。
GC堆用來分配小物件實例,它是由GC完全控制記憶體的分配和回收。 LOH堆則是為大物件實例準備的,它不會被壓縮且只在GC完全回收時才會回收。在IL中可以看到newobj、ldstr(建立string物件)、newarr(用來分配新的陣列物件)、box(裝箱)等常見的建立物件的指令。
當然在堆上也存在值類型,例如值類型作為類別的欄位時,它將儲存在堆中的實例物件空間,還有裝箱時也會讓堆上存在值類型。好了接下來我們來看看建立一個物件的記憶體分配,現在有一個Person類別和Student類別。那麼這句Student s = new Student() { studentId = 2, Id = 4 };執行完後s物件就被創建了,下面我畫了張圖來說明創建一個物件時記憶體的分配,其中s物件還有同步索引區塊與類型物件指標我沒有畫出來。
public class Person { public int Id; public void Eat() { Console.WriteLine("Eat Pear"); } } public class Student:Person { public int studentId; public void GotoSchool() { Console.WriteLine("Go to School"); } }
View Code
2.父類別物件指向子類別
我們在寫程式時為了實作多態性一般都會使用父類別物件指向子類別。那麼當我寫入Person p=new Student();時便在堆中創建了一個子類對象,下面是關於父類對象指向子類的內存分配圖。我在Person中加入了虛方法和抽象方法,並在Student子類別中重寫了方法。
從圖中可以看出一旦子類別重寫了父類別的虛方法或抽象方法,則Person方法表中的2個方法將會被子類別覆蓋,我們可根據它來實現多態性。另外在Student方法表中還有一個new void Eat()方法,不過它是無法被p呼叫的因為此時的new Eat()屬於子類別。
也就是說除了被覆寫的方法外,p只能呼叫Person方法表中的方法,如果找不到則會繼續尋找Person父類別的方法直到object。注意是不會往回找的,它不會去Student方法表中尋找方法
public abstract class Person { public int Id; public void Eat() { Console.WriteLine( "在吃梨"); } public virtual void Walk() { Console.WriteLine("在散步"); } //抽象方法只能在抽象类中声明,因此要在Person前加abstract,且只能声明并必须在子类中实现。 public abstract void Run(); } public class Student:Person { public int studentId; public void GotoSchool() { Console.WriteLine("Go to School"); } public new void Eat() { Console.WriteLine("学生 吃苹果"); } public override void Walk() { Console.WriteLine("学生 在散步"); } public override void Run() { Console.WriteLine("学生 在跑步"); } }
3.指向孫類對象
現在我再添加一個Student的子類James,從上一個例子中已經知道只有override關鍵字重寫的方法父類別才會調用,因此我將普通方法全部刪除。執行程式碼為Person p = new James() { name = “James”, studentId = 2, Id = 4 };程式碼和記憶體分配圖如下,為了突出重點,圖中我就沒有畫字段了。從結果可以看到SayHi方法最後被孫類別的SayHi覆蓋了,從這裡可以看出繼承的傳遞性!
public abstract class Person { public int Id; public virtual void Eat() { Console.WriteLine( "在吃梨"); } public virtual void Walk() { Console.WriteLine("在散步"); } //抽象方法只能在抽象类中声明,因此要在Person前加abstract,且只能声明并必须在子类中实现。 public abstract void Run(); public virtual void SayHi() { Console.WriteLine("人说:你好!"); } } public class Student:Person { public int studentId; public virtual void Eat() { Console.WriteLine("学生 在吃梨"); } public override void Walk() { Console.WriteLine("学生 在散步"); } public override void Run() { Console.WriteLine("学生 在跑步"); } } public class James:Student { public string name; public override void Eat() { Console.WriteLine("James 在吃梨"); } public override void Walk() { Console.WriteLine("James 在散步"); } public override void Run() { Console.WriteLine("James 在跑步"); } public override void SayHi() { Console.WriteLine("James说:你好!"); } }
以上就是C#基礎之記憶體分配的內容,更多相關內容請關注PHP中文網(www.php.cn)!