Object佔多少記憶體,誰也不知道,按照非託管的想法是,如果你只定義一個類,而它沒有任何資料成員,我在VS2008下,使用預設位元組對齊, class Object { }; 這樣得出來 sizeof( Object ) 為 1。 在C#裡,是不能直接獲取object佔用記憶體大小的,因為它根本不是一個標準的佈局。 而樓上的BinaryFormatter的方法,只是以二進位制格式將物件或整個連線物件圖形序列化和反序列化。它甚至還有可能包含版本資訊,所以它的結果並不能代表一個物件所佔用記憶體的大小。 C#提供了一種可以獲取一個物件的非託管記憶體的大小的方法。但是必須在顯式指定了記憶體佈局以及位元組對齊等資訊的物件上才可以使用。 現在我們定義如下物件: [StructLayout( LayoutKind.Sequential )] public class MyObject { } ,大家都知道,所有的物件都是從MyObject繼承而來的,也就是說,我們上面這個MyObject類,也隱含的繼承了Object。 那麼,現在我們看看這段程式碼: int size = Marshal.SizeOf( typeof( MyObject ) ); 執行結果是1。 看來跟C++是一樣的。也就是說,一個未定義任何資料成員的空物件,其佔用1位元組的記憶體。 那麼我們再來看看一些標準成員的大小,比如int,long,double等。 int size = Marshal.SizeOf( typeof( int ) ); //結果為4 int size = Marshal.SizeOf( typeof( long ) ); //結果為8 int size = Marshal.SizeOf( typeof( float ) ); //結果為4 int size = Marshal.SizeOf( typeof( double ) ); //結果為8 可見,這些基本資料型別,與非託管下的大小是沒有區別的。 那麼現在我們來看看混合在一起的情況。 [StructLayout( LayoutKind.Sequential )] public class MyDataObject { public byte a; public int x; public Char b; public double c; } 然後我們執行 int size = Marshal.SizeOf( typeof( MyDataObject ) ); 會發現結果是24。 為什麼是24呢,是因為我們指定了LayoutKind.Sequential,它的MSDN的說明如下: 物件的成員按照它們在被匯出到非託管記憶體時出現的順序依次佈局。這些成員根據在 System.Runtime.InteropServices.StructLayoutAttribute.Pack中指定的封裝進行佈局,並且可以是不連續的。 那麼,MyOjbect 的大小實際上就是所有資料成員記憶體位元組對齊後然後結構體的大小。 則VS2008上,位元組對齊(即StructLayoutAttribute.Pack)預設設定好像是8。 下面是MyDataObject物件在預設設定下的對齊情況: 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 4-7 b 8 8 c 16 16-23 總長度為24 現在我們來看位元組對齊為4的情況: 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 4-7 b 8 8 c 16 12-19 總長度為20。 位元組對齊為2的情況: 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 2-5 b 8 6 c 16 8-16 總長度為16。 位元組對齊為1的情況:這就是最緊湊的情況了。 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 1-4 b 8 5 c 16 6-13 總長度為14。 總體上來說,.net的物件佔用的空間,跟其它非託管程式是一樣的,只是大部分的物件,由於是託管的,而且沒有規定記憶體佈局,所以我們無法獲得其真正佔用記憶體的大小。 PS: StructLayoutAttribute類和Marshal類位於名稱空間“System.Runtime.InteropServices”下。 本來上面的對齊的排列順序,我寫的的時候中間有好幾個空格的,不知道為什麼發上來就成一個空格了,排版不好看了,效應著看吧,呵呵 //------------我也來更新一下,不知道你們兩個人在爭什麼? .net是中間語言,什麼叫做託管?託管的主要意思就是它把記憶體控制權接管了,簡之,你所寫的程式碼並不是像C/C++那樣對記憶體的精確控制。 就拿C#來說,它是號稱沒有指標,但是,實際上大家都看得出來,它的所謂引用型引數,就是指標。為什麼這麼說?你試試呼叫一個非託管的API,如果那個引數是指標型別的話,那你就得用ref了。 就拿你的問題ClassA a來說,現在我們就假定.net內部是指標,那麼 ClassA a,就相當於是定義了一個指標,我們知道,指標在32位系統下,佔4位元組。當然,這裡還有一個前提,就是ClassA是一個class,不是struct或者其它值型別。 至於string型別的成員的佔用記憶體的大小,不知道樓主你會不會C++,有沒有見過std的string是怎麼實現的?為了提交效率,降低記憶體分配頻率,string物件在建立時,就會默認了一個容量長度,這個跟它儲存的字串長度是不一樣的,如果儲存的字串長度超過了容量,那麼它會再重新分配一塊更大的記憶體來儲存。但目前我還沒看到.net的String物件的原始碼,所以不知道它的預設容量是多大,那個就應該是它預設佔的記憶體大小。我只知道StringBuilder的預設容量是16,我想string的也許更大些吧。 末了,不知道你們討論一個託管物件的佔用記憶體大小還有什麼意義。 我想你以為我這麼在一段,是哪裡COPY來吧,不好意思,我沒有COPY別人答案的習慣,全是手敲的,有空的就把我的話,當廢話看吧,我也沒什麼成見,就發表個人觀點而已。該回家吃飯了,各位,再會,
Object佔多少記憶體,誰也不知道,按照非託管的想法是,如果你只定義一個類,而它沒有任何資料成員,我在VS2008下,使用預設位元組對齊, class Object { }; 這樣得出來 sizeof( Object ) 為 1。 在C#裡,是不能直接獲取object佔用記憶體大小的,因為它根本不是一個標準的佈局。 而樓上的BinaryFormatter的方法,只是以二進位制格式將物件或整個連線物件圖形序列化和反序列化。它甚至還有可能包含版本資訊,所以它的結果並不能代表一個物件所佔用記憶體的大小。 C#提供了一種可以獲取一個物件的非託管記憶體的大小的方法。但是必須在顯式指定了記憶體佈局以及位元組對齊等資訊的物件上才可以使用。 現在我們定義如下物件: [StructLayout( LayoutKind.Sequential )] public class MyObject { } ,大家都知道,所有的物件都是從MyObject繼承而來的,也就是說,我們上面這個MyObject類,也隱含的繼承了Object。 那麼,現在我們看看這段程式碼: int size = Marshal.SizeOf( typeof( MyObject ) ); 執行結果是1。 看來跟C++是一樣的。也就是說,一個未定義任何資料成員的空物件,其佔用1位元組的記憶體。 那麼我們再來看看一些標準成員的大小,比如int,long,double等。 int size = Marshal.SizeOf( typeof( int ) ); //結果為4 int size = Marshal.SizeOf( typeof( long ) ); //結果為8 int size = Marshal.SizeOf( typeof( float ) ); //結果為4 int size = Marshal.SizeOf( typeof( double ) ); //結果為8 可見,這些基本資料型別,與非託管下的大小是沒有區別的。 那麼現在我們來看看混合在一起的情況。 [StructLayout( LayoutKind.Sequential )] public class MyDataObject { public byte a; public int x; public Char b; public double c; } 然後我們執行 int size = Marshal.SizeOf( typeof( MyDataObject ) ); 會發現結果是24。 為什麼是24呢,是因為我們指定了LayoutKind.Sequential,它的MSDN的說明如下: 物件的成員按照它們在被匯出到非託管記憶體時出現的順序依次佈局。這些成員根據在 System.Runtime.InteropServices.StructLayoutAttribute.Pack中指定的封裝進行佈局,並且可以是不連續的。 那麼,MyOjbect 的大小實際上就是所有資料成員記憶體位元組對齊後然後結構體的大小。 則VS2008上,位元組對齊(即StructLayoutAttribute.Pack)預設設定好像是8。 下面是MyDataObject物件在預設設定下的對齊情況: 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 4-7 b 8 8 c 16 16-23 總長度為24 現在我們來看位元組對齊為4的情況: 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 4-7 b 8 8 c 16 12-19 總長度為20。 位元組對齊為2的情況: 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 2-5 b 8 6 c 16 8-16 總長度為16。 位元組對齊為1的情況:這就是最緊湊的情況了。 成員 偏移位置(位元組) 記憶體分佈(位元組) a 0 0 x 4 1-4 b 8 5 c 16 6-13 總長度為14。 總體上來說,.net的物件佔用的空間,跟其它非託管程式是一樣的,只是大部分的物件,由於是託管的,而且沒有規定記憶體佈局,所以我們無法獲得其真正佔用記憶體的大小。 PS: StructLayoutAttribute類和Marshal類位於名稱空間“System.Runtime.InteropServices”下。 本來上面的對齊的排列順序,我寫的的時候中間有好幾個空格的,不知道為什麼發上來就成一個空格了,排版不好看了,效應著看吧,呵呵 //------------我也來更新一下,不知道你們兩個人在爭什麼? .net是中間語言,什麼叫做託管?託管的主要意思就是它把記憶體控制權接管了,簡之,你所寫的程式碼並不是像C/C++那樣對記憶體的精確控制。 就拿C#來說,它是號稱沒有指標,但是,實際上大家都看得出來,它的所謂引用型引數,就是指標。為什麼這麼說?你試試呼叫一個非託管的API,如果那個引數是指標型別的話,那你就得用ref了。 就拿你的問題ClassA a來說,現在我們就假定.net內部是指標,那麼 ClassA a,就相當於是定義了一個指標,我們知道,指標在32位系統下,佔4位元組。當然,這裡還有一個前提,就是ClassA是一個class,不是struct或者其它值型別。 至於string型別的成員的佔用記憶體的大小,不知道樓主你會不會C++,有沒有見過std的string是怎麼實現的?為了提交效率,降低記憶體分配頻率,string物件在建立時,就會默認了一個容量長度,這個跟它儲存的字串長度是不一樣的,如果儲存的字串長度超過了容量,那麼它會再重新分配一塊更大的記憶體來儲存。但目前我還沒看到.net的String物件的原始碼,所以不知道它的預設容量是多大,那個就應該是它預設佔的記憶體大小。我只知道StringBuilder的預設容量是16,我想string的也許更大些吧。 末了,不知道你們討論一個託管物件的佔用記憶體大小還有什麼意義。 我想你以為我這麼在一段,是哪裡COPY來吧,不好意思,我沒有COPY別人答案的習慣,全是手敲的,有空的就把我的話,當廢話看吧,我也沒什麼成見,就發表個人觀點而已。該回家吃飯了,各位,再會,