国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 編程設(shè)計(jì) > 正文

建站.Net常識 詳談值類型和引用類型

2020-06-27 15:42:02
字體:
供稿:網(wǎng)友

值類型和引用類型是.net里面的一個基本概念
在面試的時候也經(jīng)常遇到
關(guān)于這個概念有很多誤解,經(jīng)常聽到下面的說法
1.兩者的區(qū)別是值類型分配在堆棧上,引用類型分配在堆上
  這句話不對,至少不準(zhǔn)確
2.值類型性能更好,
  這句話要考慮情況
先補(bǔ)充一些背景資料
常見的值類型有:大部分原生類型,例如int float long 各種自己定義的結(jié)構(gòu)體等等
常見的引用類型有:string 各種Class 數(shù)組(包括int[]這種的)
堆棧:在這里指的是執(zhí)行堆棧
堆:在這里指的是托管堆,就是LOH+G0+G1+G2
讓我們先來看看第一點(diǎn):兩者的區(qū)別是值類型分配在堆棧上,引用類型分配在堆上
1.假設(shè)在一個方法里面有一個語句是 var obj = new object();
首先 new 出來的Object將被存放在堆中
obj在堆棧上,其內(nèi)容是一個指針,指向new 出來的那個Object
2.然后假設(shè)在一個方法里面有一個語句是 var i =1 ;
這里的 i 在堆棧上, 其值是1 (int 類型)
3.類中的值類型成員,例如以下一個定義
public class ClassA
{
private int i = 1;
}
假設(shè)在一個方法里面有一個語句是 var obj = new ClassA();
首先 new 出來的ClassA將被存放在堆中
obj在堆棧上,其內(nèi)容是一個指針,指向new 出來的那個ClassA
ClassA中的成員 i 這個時候也在堆上
假設(shè)有一個有一個其他語句使用到ClassA.i 這個i的值才會被拷貝到堆棧上(大部分默認(rèn)的情況)
4.將引用類型放在堆棧上
unsafe
{
var obj = stackalloc int[100];
}
stackalloc是用來在堆棧上分配內(nèi)存的keyword
上面的4個例子正好證明了 引用類型和值類型都可以存在在堆和堆棧上
不過大部分時候都是情況1和2, 所以大部分引用類型都在堆上,大部分
讓我們先來看看第二點(diǎn):值類型性能更好
就上面的情況1,2而言
a.在取一個對象的時候,情況1先讀取obj的值, 這是一個地址,然后要重新讀取該地址的真正的對象Object
情況2讀取obj的值,這就是真正的值了,所以相對數(shù)據(jù)比較快
b.在堆中的對象受到GC的影響,需要額外的CPU資源;(堆棧中的對象,出棧以后釋放掉了)
c.在堆中的對象需要等到GC后才被釋放,所以暫用內(nèi)存時間較久
其他情況:
1.考慮一些情況,裝箱拆箱;這是值類型在堆棧和對中拷貝時特有的操作,該操作還是非常消耗資源的
  那么如果無法避免裝箱拆箱,就要考慮避免使用值類型了
2.值類型傳遞的時候每次都是值拷貝,如果某個值類型很大(例如自己定義的struct) 那么這個性能也是個問題;(而且還要考慮到堆棧有大小限制)
  所以一般情況下比較復(fù)雜的類型都只能用class
3.許多時候,引用比較都比值比較來的快,因?yàn)橐帽容^只要看看兩個地址是否相等
  而值比較卻要考慮里面真實(shí)的值
值類型和引用類型的區(qū)別其實(shí)從他們的名字上就看的出來
在傳遞值類型的時候傳遞的是真實(shí)值,這也就意味著原來的值被復(fù)制了一份到新的位置
而在傳遞引用類型的時候傳遞的是引用(地址),這里并沒有復(fù)制一份原來值的動作,因此兩個引用都指向一個對象
Ref
在沒有Ref的時候傳遞參數(shù),CLR會為每個參數(shù)弄一個臨時變量出來,存儲值類型的值或者是引用類型的指針
這種情況下修改值類型或者引用類型的值不會影響到原來的值
但是修改引用類型的成員會影響到原來的值,下面兩個例子分別是修改參數(shù)成員和修改參數(shù)本身
?
public class ClassA
{
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
ClassA a = new ClassA();
Test(a);
Console.WriteLine(a.Name);//這里會輸出mark
}
private static void Test(ClassA a)
{
a.Name = "Mark";
}
}
?
public class ClassA
{
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
ClassA a = new ClassA();
Test(a);
Console.WriteLine(a.Name);//這里不會輸出Liu
}
private static void Test(ClassA a)
{
a = new ClassA() { Name = "Liu" };
}
}
  
在有REF的情況下傳遞參數(shù),CLR就會把原來的變量的地址傳遞過去,如果修改了該變量會影響到原來的成員
?
public class ClassA
{
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
ClassA a = new ClassA();
Test(ref a);
Console.WriteLine(a.Name);//這里會輸出Liu
}
private static void Test(ref ClassA a)
{
a = new ClassA() { Name = "Liu" };
}
}
  
備注1:如何確定一個對象在堆上或者是堆棧上
剛才說的都是理論,這邊是驗(yàn)證
使用WinDBG+SOS附加到一個.net程序上;然后查看堆中的情況;
具體指令就不說了,大家查看一下幫助

值類型,引用類型,建站,.Net

值類型,引用類型,建站,.Net


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 吉隆县| 五峰| 玉溪市| 汉川市| 宁河县| 玉田县| 时尚| 垣曲县| 浦北县| 稷山县| 天气| 虞城县| 邵阳市| 漳浦县| 怀化市| 子洲县| 临潭县| 邯郸市| 灵山县| 塔城市| 孟连| 赤壁市| 青铜峡市| 兴文县| 班戈县| 长宁区| 柘城县| 林州市| 同仁县| 江门市| 水富县| 临澧县| 广安市| 鹤壁市| 威远县| 盐亭县| 十堰市| 临海市| 平潭县| 平顶山市| 喀喇|