1. 程式人生 > >C# 獲取物件 大小 Marshal.SizeOf (sizeof 只能在不安全的上下文中使用)

C# 獲取物件 大小 Marshal.SizeOf (sizeof 只能在不安全的上下文中使用)

C# 能否獲取一個物件所佔記憶體的大小?
今日,在專案重構的時候忽然想到一個問題,一個類哪些成員的增加,會影響一個類所佔記憶體的大小?C#有沒有辦法知道一個物件佔多少記憶體呢?

 第一個問題:很快想到是類的非靜態的欄位、屬性。

 第二個問題:首先想到的是sizeof()。

下面開始驗證,首先來驗證值型別,驗證程式碼如下:

int size = sizeof (int); //4個位元組
注意點:sizeof 運算子僅適用於值型別,而不適用於引用型別。sizeof 運算子只能在不安全程式碼塊中使用。如下面的程式碼將無法編譯通過:

public struct TestStuct
{

}

int size = sizeof(new TestStuct());
編譯後,提示:

錯誤 1 “ConsoleApplication3.TestStuct”沒有預定義的大小,因此 sizeof 只能在不安全的上下文中使用(請考慮使用 System.Runtime.InteropServices.Marshal.SizeOf)

修改為Marshal.SizeOf方法,改方法返回物件的非託管大小(以位元組為單位)。引數可以是引用型別或裝箱的值型別。佈局必須是連續的或顯式的。

int size = Marshal.SizeOf(new TestStuct()); //1個位元組
接下來來驗證引用型別:

由於不能作為非託管結構進行封送處理;無法計算有意義的大小或偏移量。所有下面的程式碼在執行的時候,會丟擲異常。

public class Student
{
}

int size = Marshal.SizeOf(new Student());
需要給Student類,加上一個StructLayoutAttribute,來控制Student類的資料欄位的物理佈局。修改程式碼為:

[StructLayout(LayoutKind.Sequential)]
public class Student
{
}

int size = Marshal.SizeOf(new Student()); //1個位元組
LayoutKind 預設值為Auto.

結論:
1:對於託管物件是沒有辦法直接獲取到一個物件所佔的記憶體大小。
2:非託管物件,可以使用Marshal.SizeOf
3:對內建型別,如int,long,byte等使用sizeof

擴充套件:
有人提出使用二進位制序列化,將一個物件序列化成一個MemoryStream,然後返回MemoryStream.Length,經過驗證是不可以的。

驗證程式碼如下:

複製程式碼
[Serializable]
public class Student
{
}

private static long GetObjectSize(object o)
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, o);
using (var fileStream = new FileStream(@"D:\Student.txt", FileMode.OpenOrCreate, FileAccess.Write))
{
var buffer = stream.ToArray();
fileStream.Write(buffer, 0, buffer.Length);
fileStream.Flush();
}

            return stream.Length;
        }
    }

var student = new Student();
long size = GetObjectSize(student); //139個位元組
複製程式碼
Student.txt儲存的文字資訊如下所示,通過文字資訊,可以得知多出來的100多個位元組,估計是就是這一串字串吧