值类型 引用类型 堆栈 堆 之 异想
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                值类型 引用类型  堆栈 堆 之 异想
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.                        
                                
                            
                            
                            看了很多值類型 和 引用類型的文章(谷歌能搜索出來的) 看了越多疑問越大,而這些資料中沒有具體的說明。 問題: 1、堆棧 和 堆 分別存于計算機(jī)的哪個硬件(CPU緩存,內(nèi)存,硬盤)? 2、為什么只有值類型和引用類型? 3、為什么說引用類型是指針? 4、堆棧必堆小小多少?  以下是個人的分析,不是權(quán)威結(jié)果。 1、堆棧 和 堆 分別存于計算機(jī)的哪個硬件(CPU緩存,內(nèi)存,硬盤)? 使用排除法來看這個問題 (1)CPU緩存 (2)內(nèi)存 (3)硬盤  (3)可以排除堆棧的可能,因為 硬盤最慢 (2)最有可能存堆棧,因為 速度適中,且相對來說存儲空間足夠大  (1)可能性很小,應(yīng)為僅幾年來CPU的緩存越來越大 但目前家用級別的CPU的1,2,3級緩存很少超過10MB(多核情況下每個核心分到的更少);   真像可能就是堆棧和堆都是放在內(nèi)存里的。  那么為什么堆棧比堆快呢? 個人認(rèn)為這情況和hashtable與list等數(shù)據(jù)容器的差異,差不多。 存取方式?jīng)Q定的。 堆棧:只能存取值類型,且先進(jìn)先出,不夠的時候直接壓棧(就像"向右看起"的命令一樣) --簡單快捷 堆:首先,堆的分配模式會存在碎片,并不是連續(xù)性的(這里直的是多個對象,找到一個適合的內(nèi)存空間就把對象放進(jìn)去,就像家居擺放物件一樣,有時候不貼個紙條的話,得找半天)。  2、為什么只有值類型和引用類型? 這個我覺得追溯到本源比較好解釋,就是CPU只能進(jìn)行數(shù)學(xué)計算。(看下匯編代碼會好理解些) 值類型:就是數(shù)字,CPU可以直接進(jìn)行運算。 引用類型:最終指向值類型的指針。object是指針,object的ToString的函數(shù)還是一個指針,ToString內(nèi)有String類型還是指針,最終指向一個Char[] 字符集合 (注,我對String的理解就是Char[])。 所以對象無法直接進(jìn)行運算,只能通過指針找到能運算的部分,再進(jìn)行運算。這也就是為啥只有2個類型了,一個是值用于運算,一個是指針,指向需要運算的地方。  3、為什么說引用類型是指針? 由上可知,引用類型是指針必然性。 一個Class內(nèi)除了Int32等 值類型外其他皆是指針,委托,函數(shù),函數(shù)內(nèi)的對象,屬性,事件 都是指針。 根據(jù)這種特性,指針(引用類型)作為參數(shù)傳遞,出來的時候會根據(jù)函數(shù)內(nèi)的改變而改變,而值要作為參數(shù)輸入并輸出的話就要ref了。 (注: 個人發(fā)現(xiàn) DateTime 作為參數(shù)時具有值類型的特征)  4、堆棧必堆小小多少? 未知,希望有知道的朋友能給出測試方法或者結(jié)果 我的推測是既然是在內(nèi)存,必然沒有限制,除非人為的限制 我使用線程測試內(nèi)存上限時發(fā)現(xiàn)沒有具體的上限。我的是64位+8G內(nèi)存的筆記本以下是測試結(jié)果:(線程內(nèi)分別創(chuàng)建class和sturct) X86: 一個應(yīng)用程序只能達(dá)到1300多一點的線程,再也上不去了,提交內(nèi)存約1440k class:運行穩(wěn)定。sturct:大約2分鐘 內(nèi)存溢出 X64:一個應(yīng)用程序只能達(dá)到8000多的線程,提交內(nèi)存約10000k(還能繼續(xù)) class:運行穩(wěn)定。sturct:行穩(wěn)定   最終 我的結(jié)論:在C#里class 和sturct 如果真的是一個分配在堆,一個分配在堆棧,那么堆棧和堆的空間大小沒有區(qū)別,只存在速度的區(qū)別  以下是測試代碼:     using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 10000; i++)
{
Thread th = new Thread(() =>
{
abc a = new abc(1);
});
th.Start();
}
Console.ReadKey();
}
}
struct abc
{
public abc(Int32 x)
{
ds = String.Empty;
Test();
}
String ds;
private void Test()
{
while (true)
{
ds += "A";
Thread.Sleep(1000);
}
}
}
class bc
{
public bc(Int32 x)
{
ds = String.Empty;
Test();
}
String ds;
private void Test()
{
while (true)
{
ds += "A";
Thread.Sleep(1000);
}
}
}
} IL:
                        
                        
                        using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 10000; i++)
{
Thread th = new Thread(() =>
{
abc a = new abc(1);
});
th.Start();
}
Console.ReadKey();
}
}
struct abc
{
public abc(Int32 x)
{
ds = String.Empty;
Test();
}
String ds;
private void Test()
{
while (true)
{
ds += "A";
Thread.Sleep(1000);
}
}
}
class bc
{
public bc(Int32 x)
{
ds = String.Empty;
Test();
}
String ds;
private void Test()
{
while (true)
{
ds += "A";
Thread.Sleep(1000);
}
}
}
} IL:
class 的
// 代碼大小 28 (0x1c) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: nop IL_0008: ldarg.0 IL_0009: ldsfld string [mscorlib]System.String::Empty IL_000e: stfld string ConsoleApplication1.bc::ds IL_0013: ldarg.0 IL_0014: call instance void ConsoleApplication1.bc::Test() IL_0019: nop IL_001a: nop IL_001b: ret } // end of method bc::.ctor sturct 的 // 代碼大小 20 (0x14) .maxstack 8 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldsfld string [mscorlib]System.String::Empty IL_0007: stfld string ConsoleApplication1.abc::ds IL_000c: ldarg.0 IL_000d: call instance void ConsoleApplication1.abc::Test() IL_0012: nop IL_0013: ret } // end of method abc::.ctor 堆棧容量測試: using System; using System.Threading; namespace ConsoleApplication1 {class Program{static void Main(string[] args){String txt = System.IO.File.ReadAllText("demo.txt");//一個3.11MB的文本 Thread th = new Thread(() =>{abc a = new abc(1);for (var i = 0; i < 1000; i++){a.ds += txt;}});th.Start();Console.ReadKey();}}struct abc{public abc(Int32 x){ds = String.Empty;}public String ds;}}測試結(jié)果:X64 能 提交內(nèi)存3000K以上
?
我的結(jié)論和想法是這樣的:
首先我是站在CPU的角度去思考的。
1、堆棧 堆 可能都是一樣的指針,他們本身只是數(shù)據(jù)容器。
2、他們的區(qū)別在于存取方式不一致導(dǎo)致的存取速度不一樣。
3、堆棧 和堆 沒有具體大小,除非人為設(shè)置,且很有可能由CLR或者編譯器動態(tài)選擇數(shù)據(jù)容器。(畢竟我只能看到IL,看不到先X86反編譯匯編)
4、值類型傳參實為傳值,引用類型傳參實為傳地址(指針),這也是堆棧和堆數(shù)據(jù)使用上的區(qū)別。CPU對堆棧的態(tài)度是拿來就用,對堆就是找到再用。
通過 Wiz 發(fā)布轉(zhuǎn)載于:https://www.cnblogs.com/tianjing/archive/2012/07/03/2574577.html
總結(jié)
以上是生活随笔為你收集整理的值类型 引用类型 堆栈 堆 之 异想的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: vs2008中combox用法总结
- 下一篇: command line
