ASP.NET堆和棧二之值類型和引用類型的參數(shù)傳遞和內(nèi)存分配
".NET的堆和棧"系列:
ASP.NET堆和棧二之值類型和引用類型參數(shù)傳遞和內(nèi)存分配
ASP.NET堆和棧三之引用類型對(duì)象拷貝和內(nèi)存分配
ASP.NET堆和棧四之對(duì)托管和非托管資源垃圾的回收和內(nèi)存分配
在" ASP.NET堆和棧一之基本概念和值類型內(nèi)存分配"中,了解了"堆"和"棧"的基本概念,以及值類型的內(nèi)存分配。我們知道:當(dāng)執(zhí)行一個(gè)方法的時(shí)候,值類型實(shí)例會(huì)在"棧"上分配內(nèi)存,而引用類型實(shí)例會(huì)在"堆"上分配內(nèi)存,當(dāng)方法執(zhí)行完畢,"棧"上的實(shí)例由操作系統(tǒng)自動(dòng)釋放,"堆"上的實(shí)例由.NET Framework的GC進(jìn)行回收。而本篇的重點(diǎn)要放在:值類型和引用類型參數(shù)的傳遞,以及內(nèi)存分配。
傳遞值類型參數(shù)
class Class1 { public void Go() { int x = 5; AddFive(x); Console.WriteLine(x.ToString()); } public int AddFive(int pValue) { pValue += 5; return pValue; } }
大致過(guò)程如下:
1、值類型變量x被放到"棧"上。
2、開始執(zhí)行AddFive()方法,值類型變量pValue被放到"棧"上,并把x的值賦值給pValue,pValue的值變成了5。
3、繼續(xù)執(zhí)行AddFive()方法,pValue的值變成了10。
4、執(zhí)行完AddFive()方法,釋放pValue的內(nèi)存,"棧"指針回到x,線程重新回到Go()方法中。
輸出結(jié)果:5
以上,在傳遞值類型參數(shù)x的時(shí)候,實(shí)際上是把x一個(gè)字節(jié)一個(gè)字節(jié)地拷貝給pValue。
傳遞容易造成"棧溢出"的值類型參數(shù),在值類型參數(shù)前加關(guān)鍵字ref
public struct MyStruct { long a, b, c, d, e, f, g, h, i, j, k, l, m; } public void Go() { MyStruct x = new MyStruct(); DoSomething(x); } public void DoSomething(MyStruct pValue) { // DO SOMETHING HERE.... }
假設(shè)以上的值類型struct足夠大,而x和pValue都會(huì)被分配到"棧"上,這時(shí)可能造成"棧溢出"。
如何避免呢?
--解決辦法是讓DoSomething傳遞一個(gè)ref類型參數(shù)。這樣寫:
public struct MyStruct { long a, b, c, d, e, f, g, h, i, j, k, l, m; } public void Go() { MyStruct x = new MyStruct(); x.a = 5; DoSomething(ref x); Console.WriteLine(x.a.ToString()); } public void DoSomething(ref MyStruct pValue) { pValue.a = 12345; }
使用ref后,執(zhí)行DoSomething(ref x),是把x的地址賦值給了pValue,即pValue和x指向了同一個(gè)引用地址。當(dāng)改變pValue的值,變化也會(huì)反映到x中。
輸出結(jié)果:12345
以上,為了避免"大型"值類型參數(shù)傳遞時(shí)造成的"棧溢出",可以在值類型前面加ref關(guān)鍵字,于是,在傳遞值類型參數(shù)x的時(shí)候,實(shí)際上是把x本身的棧地址拷貝給pValue,x和pValue指向同一個(gè)棧地址。
傳遞引用類型參數(shù)
傳遞引用類型參數(shù)的道理和在傳遞的值類型參數(shù)前面加ref關(guān)鍵字是一樣的。
public class MyInt { public int MyValue; } public void Go() { MyInt x = new MyInt(); x.MyValue = 2; DoSomething(x); Console.WriteLine(x.MyValue.ToString()); } public void DoSomething(MyInt pValue) { pValue.MyValue = 12345; }
輸出結(jié)果:12345
以上大致過(guò)程是這樣:
1、在托管堆上創(chuàng)建一個(gè)MyInt類型的實(shí)例
2、在棧上創(chuàng)建一個(gè)MyInt類型的變量x指向堆上的實(shí)例
3、把托管堆上的公共字段MyValue賦值為2
4、通過(guò)DoSomething(x)方法,把x的引用地址賦值給pValue,即pValue和x指向同一個(gè)引用地址
5、改變pValue的值,也會(huì)反映到x上
以上,在傳遞引用類型參數(shù)x的時(shí)候,實(shí)際上是把x指向托管堆實(shí)例的引用地址拷貝給pValue,x和pValue指向同一個(gè)托管堆實(shí)例地址。
傳遞引用類型參數(shù),在引用類型參數(shù)之前加關(guān)鍵字ref
public class Thing { } public class Animal:Thing { public int Weight; } public class Vegetable:Thing { public int Length; } public void Go() { Thing x = new Animal(); Switcharoo(ref x); Console.WriteLine("x is Animal : " + (x is Animal).ToString()); Console.WriteLine("x is Vegetable : " + (x is Vegetable).ToString()); } public void Switcharoo(ref Thing pValue) { pValue = new Vegetable(); }
輸出結(jié)果:
x is Animal : False
x is Vegetable : True
以上大致過(guò)程是這樣:
1、在托管堆上創(chuàng)建Animal對(duì)象實(shí)例。
2、在棧上創(chuàng)建類型為Thing的x變量指向Animal實(shí)例的引用地址。
3、通過(guò)Switcharoo(ref x)方法把x本身的地址賦值給pValue,至此,pValue和x指向了相同的棧內(nèi)存地址,任何一方的變化都會(huì)反映到另外一方。
4、在Switcharoo(ref Thing pValue)內(nèi)部,在托管堆上創(chuàng)建Vegetable對(duì)象實(shí)例。
5、pValue指向Vegetable實(shí)例,也就相當(dāng)于x指向Vegetable實(shí)例。
以上,當(dāng)在引用類型參數(shù)之前加上關(guān)鍵字ref,再傳遞,是把x本身的棧地址拷貝給pValue,x和pValue指向同一個(gè)棧地址。
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
JWT + ASP.NET MVC時(shí)間戳防止重放攻擊詳解
這篇文章主要給大家介紹了關(guān)于JWT + ASP.NET MVC時(shí)間戳防止重放攻擊發(fā)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07.NET微信公眾號(hào)開發(fā)之準(zhǔn)備工作
本文是.NET微信公眾號(hào)開發(fā)系列文章的第一篇,主要給大家簡(jiǎn)單介紹下微信公眾號(hào)的一些操作,有需要的小伙伴可以參考下。2015-07-07Entity Framework使用Code First模式管理存儲(chǔ)過(guò)程
本文詳細(xì)講解了Entity Framework使用Code First模式管理存儲(chǔ)過(guò)程的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03CommunityServer又稱CS論壇的相關(guān)學(xué)習(xí)資料
以前項(xiàng)目需要整合這個(gè)論壇,同事找了一些資料,現(xiàn)在放上來(lái),并說(shuō)下自己對(duì)這個(gè)論壇的看法。2009-05-05獲取asp.net服務(wù)器控件的客戶端ID和Name的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇獲取asp.net服務(wù)器控件的客戶端ID和Name的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05在asp.net中操作sql server數(shù)據(jù)庫(kù)的一些小技巧
在asp.net中操作sql server數(shù)據(jù)庫(kù)的一些小技巧...2006-09-09asp.net AJAX實(shí)現(xiàn)無(wú)刷新獲得數(shù)據(jù)
提供一個(gè)使用AJAX實(shí)現(xiàn)無(wú)刷新判斷注冊(cè)用戶名是否被注冊(cè)的代碼:2008-11-11