ค้นหาขนาดของอินสแตนซ์วัตถุเป็นไบต์ใน c #


114

สำหรับอินสแตนซ์ตามอำเภอใจใด ๆ (คอลเลกชันของวัตถุที่แตกต่างกันองค์ประกอบวัตถุเดี่ยว ฯลฯ )

ฉันจะกำหนดขนาดเป็นไบต์ได้อย่างไร

(ขณะนี้ฉันมีคอลเล็กชันของวัตถุต่างๆและฉันกำลังพยายามกำหนดขนาดรวมของมัน)

แก้ไข: มีคนเขียนวิธีการขยายสำหรับ Object ที่สามารถทำได้หรือไม่? นั่นจะเป็น imo ที่ค่อนข้างเรียบร้อย



คำตอบ:


60

ก่อนอื่นคำเตือน: สิ่งต่อไปนี้เป็นสิ่งที่เคร่งครัดในขอบเขตของการแฮ็กที่น่าเกลียดและไม่มีเอกสาร อย่าพึ่งพาการทำงานนี้แม้ว่าจะใช้ได้กับคุณในตอนนี้ แต่ก็อาจหยุดทำงานในวันพรุ่งนี้ด้วยการอัปเดต. NET เล็กน้อยหรือที่สำคัญ

คุณสามารถใช้ข้อมูลในบทความนี้เกี่ยวกับ CLR internals MSDN Magazine Issue 2005 พฤษภาคม - เจาะลึก. NET Framework Internals เพื่อดูว่า CLR สร้าง Runtime Objects อย่างไร - ล่าสุดที่ฉันตรวจสอบก็ยังใช้ได้ นี่คือวิธีการดำเนินการ (จะดึงฟิลด์ "ขนาดอินสแตนซ์พื้นฐาน" ภายในผ่านทางTypeHandleประเภท)

object obj = new List<int>(); // whatever you want to get the size of
RuntimeTypeHandle th = obj.GetType().TypeHandle;
int size = *(*(int**)&th + 1);
Console.WriteLine(size);

สิ่งนี้ใช้ได้กับ 3.5 SP1 32 บิต ฉันไม่แน่ใจว่าขนาดเขตข้อมูลบน 64 บิตเหมือนกันหรือไม่คุณอาจต้องปรับประเภทและ / หรือออฟเซ็ตหากไม่เป็นเช่นนั้น

ซึ่งจะใช้ได้กับประเภท "ปกติ" ทั้งหมดซึ่งอินสแตนซ์ทั้งหมดมีประเภทที่กำหนดไว้อย่างดีเหมือนกัน สิ่งที่ไม่เป็นความจริงคืออาร์เรย์และสตริงแน่นอนและฉันก็เชื่อเช่นStringBuilderกัน สำหรับพวกเขาคุณจะต้องเพิ่มขนาดขององค์ประกอบที่มีทั้งหมดเป็นขนาดอินสแตนซ์พื้นฐาน


ไม่ไม่มีวิธีที่ "เหมาะสม" ในการดำเนินการนี้เนื่องจากไม่ใช่สิ่งที่แอปพลิเคชัน. NET ที่มีพฤติกรรมดีควรเป็นห่วงในตอนแรก สิ่งที่กล่าวมาข้างต้นโดยตรงกับโครงสร้างข้อมูลภายในของการใช้งาน CLR เฉพาะ (ซึ่งอาจเปลี่ยนแปลงได้ง่ายใน. NET เวอร์ชันถัดไป)
Pavel Minaev

3
สิ่งนี้ควรจะทำงานใน C # หรือเฉพาะ c ++ ที่มีการจัดการ? ยังไม่มีความสุขใน C # เท่าที่ฉันได้ลอง:Cannot take the address of, get the size of, or declare a pointer to a managed type ('System.RuntimeTypeHandle')
Maslow

17
NET 4 เวอร์ชันนี้ไม่จำเป็นต้องใช้รหัสที่ไม่ปลอดภัยด้วยซ้ำ: Marshal.ReadInt32(type.TypeHandle.Value, 4)ใช้ได้กับ x86 และ x64 ฉันทดสอบเฉพาะประเภทโครงสร้างและคลาสเท่านั้น โปรดทราบว่าสิ่งนี้ส่งคืนขนาดบรรจุกล่องสำหรับชนิดค่า @Pavel บางทีคุณอาจจะปรับปรุงคำตอบของคุณ
jnm2

2
@ sab669 ให้แทนที่typeด้วยobj.GetType()ในตัวอย่างของเขา ไม่สำคัญว่าคุณจะใช้เฟรมเวิร์กใดมีเพียง CLR (v2 หรือ v4 หรือ CoreCLR) เท่านั้น ฉันยังไม่ได้ลองใช้กับ CoreCLR
jnm2

2
@SamGoldberg การคำนวณสิ่งนี้ด้วยตนเองเป็นงานจำนวนมากกับกรณีขอบล้าน Sizeof บอกขนาดคงที่ของวัตถุไม่ใช่การใช้หน่วยความจำของกราฟรันไทม์ของวัตถุ หน่วยความจำและโปรไฟล์ CPU ของ VS2017 นั้นดีมากเช่นเดียวกับ ReSharper และเครื่องมืออื่น ๆ และนั่นคือสิ่งที่ฉันใช้วัด
jnm2

21

คุณอาจประมาณขนาดได้โดยแกล้งทำเป็นซีเรียลไลเซอร์ไบนารี (แต่กำหนดเส้นทางเอาต์พุตไปที่การลืม) หากคุณกำลังทำงานกับอ็อบเจ็กต์ที่สามารถต่ออนุกรมกันได้

class Program
{
    static void Main(string[] args)
    {
        A parent;
        parent = new A(1, "Mike");
        parent.AddChild("Greg");
        parent.AddChild("Peter");
        parent.AddChild("Bobby");

        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
           new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        SerializationSizer ss = new SerializationSizer();
        bf.Serialize(ss, parent);
        Console.WriteLine("Size of serialized object is {0}", ss.Length);
    }
}

[Serializable()]
class A
{
    int id;
    string name;
    List<B> children;
    public A(int id, string name)
    {
        this.id = id;
        this.name = name;
        children = new List<B>();
    }

    public B AddChild(string name)
    {
        B newItem = new B(this, name);
        children.Add(newItem);
        return newItem;
    }
}

[Serializable()]
class B
{
    A parent;
    string name;
    public B(A parent, string name)
    {
        this.parent = parent;
        this.name = name;
    }
}

class SerializationSizer : System.IO.Stream
{
    private int totalSize;
    public override void Write(byte[] buffer, int offset, int count)
    {
        this.totalSize += count;
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return true; }
    }

    public override void Flush()
    {
        // Nothing to do
    }

    public override long Length
    {
        get { return totalSize; }
    }

    public override long Position
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        throw new NotImplementedException();
    }

    public override long Seek(long offset, System.IO.SeekOrigin origin)
    {
        throw new NotImplementedException();
    }

    public override void SetLength(long value)
    {
        throw new NotImplementedException();
    }
}

6
แน่นอนว่านี่อาจทำให้คุณได้ขนาดขั้นต่ำ แต่ไม่ได้บอกอะไรเกี่ยวกับขนาดในหน่วยความจำ
John Saunders

ฮ่า ๆ หลอดไฟถัดไปที่ฉันมีก่อนที่จะกลับมาตรวจสอบคำตอบนั้นใช้ตัวต่ออนุกรมไบนารี จอห์นนี่จะไม่ให้ขนาดที่แท้จริงในหน่วยความจำได้อย่างไร?
เจนี่

2
มันจะให้ขนาดซีเรียลไลซ์ซึ่งจะเป็นขนาดที่ซีเรียลไลเซอร์ต้องการสำหรับวัตถุประสงค์ "ซีเรียลไลเซอร์" สิ่งเหล่านี้น่าจะแตกต่างจากจุดประสงค์ "sit-in-memory" บางที serializer จะเก็บจำนวนเต็มขนาดเล็กในสามไบต์เช่น
John Saunders

5
อย่างที่ฉันพูดมันเป็นเพียงการประมาณเท่านั้น มันไม่สมบูรณ์แบบ แต่ฉันไม่เห็นด้วยที่มันบอกคุณว่า "ไม่มีอะไร" เกี่ยวกับขนาดในหน่วยความจำ ฉันจะบอกว่ามันให้คุณบางความคิด - serializations ขนาดใหญ่จะโดยทั่วไปจะมีความสัมพันธ์กับขนาดใหญ่ขนาดในหน่วยความจำ มีความสัมพันธ์บางอย่าง
BlueMonkMN

ฉันเห็นด้วย - การหา ballpark โดยประมาณขนาดของกราฟออบเจ็กต์. NET มีประโยชน์
Craig Shearer

8

สำหรับชนิดที่ไม่มีการจัดการ aka value types โครงสร้าง:

        Marshal.SizeOf(object);

สำหรับวัตถุที่มีการจัดการสิ่งที่ฉันเข้าใกล้คือการประมาณ

        long start_mem = GC.GetTotalMemory(true);

        aclass[] array = new aclass[1000000];
        for (int n = 0; n < 1000000; n++)
            array[n] = new aclass();

        double used_mem_median = (GC.GetTotalMemory(false) - start_mem)/1000000D;

อย่าใช้การทำให้เป็นอนุกรมฟอร์แมตเตอร์ไบนารีจะเพิ่มส่วนหัวดังนั้นคุณสามารถเปลี่ยนคลาสของคุณและโหลดไฟล์ซีเรียลไลซ์เก่าลงในคลาสที่แก้ไขได้

นอกจากนี้ยังไม่บอกขนาดจริงในหน่วยความจำและไม่คำนึงถึงการจัดตำแหน่งหน่วยความจำ

[แก้ไข] ด้วยการใช้ BiteConverter.GetBytes (prop-value) แบบวนซ้ำในทุกคุณสมบัติของชั้นเรียนของคุณคุณจะได้รับเนื้อหาเป็นไบต์ซึ่งไม่นับน้ำหนักของคลาสหรือการอ้างอิง แต่ใกล้เคียงกับความเป็นจริงมากขึ้น ฉันอยากจะแนะนำให้ใช้อาร์เรย์ไบต์สำหรับข้อมูลและคลาสพร็อกซีที่ไม่มีการจัดการเพื่อเข้าถึงค่าโดยใช้การคัดเลือกตัวชี้หากขนาดมีความสำคัญโปรดทราบว่าจะเป็นหน่วยความจำที่ไม่อยู่ในแนวเดียวกันดังนั้นในคอมพิวเตอร์เครื่องเก่าจะช้า แต่ชุดข้อมูลขนาดใหญ่บน RAM MODERN จะเป็น เร็วกว่ามากเนื่องจากการย่อขนาดเพื่ออ่านจาก RAM จะส่งผลกระทบที่ใหญ่กว่าการไม่จัดแนว


5

สิ่งนี้ไม่ได้นำไปใช้กับการใช้งาน. NET ในปัจจุบัน แต่สิ่งหนึ่งที่ควรคำนึงถึงในการรวบรวม / จัดการขยะคือขนาดที่จัดสรรของวัตถุสามารถเปลี่ยนแปลงได้ตลอดอายุการใช้งานของโปรแกรม ตัวอย่างเช่นตัวเก็บขยะบางรุ่น (เช่นตัวเก็บรวบรวมไฮบริดสำหรับการนับรุ่น / การอ้างอิงภายนอกภายนอกภายนอกภายนอก) จะต้องจัดเก็บข้อมูลบางอย่างหลังจากย้ายวัตถุจากเรือนเพาะชำไปยังพื้นที่ที่เจริญเติบโตเต็มที่แล้วเท่านั้น

ทำให้ไม่สามารถสร้าง API ทั่วไปที่เชื่อถือได้เพื่อแสดงขนาดวัตถุ


น่าสนใจ. แล้วผู้คนทำอะไรเพื่อกำหนดขนาดของวัตถุ / คอลเลกชันของวัตถุแบบไดนามิก?
เจนี่

2
ขึ้นอยู่กับสิ่งที่พวกเขาต้องการ ถ้าสำหรับ P / Invoke (การทำงานร่วมกันของโค้ดเนทีฟ) พวกเขาใช้ Marshal.SizeOf (typeof (T)) หากสำหรับการทำโปรไฟล์หน่วยความจำพวกเขาใช้ตัวสร้างโปรไฟล์แยกต่างหากที่ทำงานร่วมกับสภาพแวดล้อมการดำเนินการเพื่อให้ข้อมูล หากคุณสนใจการจัดตำแหน่งองค์ประกอบในอาร์เรย์คุณสามารถใช้ตัวเลือก SizeOf IL ใน DynamicMethod (ฉันไม่คิดว่าจะมีวิธีที่ง่ายกว่านี้ในกรอบงาน. NET สำหรับสิ่งนี้)
Sam Harwell

5

ปลอดภัยในการแก้ปัญหาด้วยการเพิ่มประสิทธิภาพบาง CyberSaving / รหัส บางกรณี:

/* test nullable type */      
TestSize<int?>.SizeOf(null) //-> 4 B

/* test StringBuilder */    
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) sb.Append("わたしわたしわたしわ");
TestSize<StringBuilder>.SizeOf(sb ) //-> 3132 B

/* test Simple array */    
TestSize<int[]>.SizeOf(new int[100]); //-> 400 B

/* test Empty List<int>*/    
var list = new List<int>();  
TestSize<List<int>>.SizeOf(list); //-> 205 B

/* test List<int> with 100 items*/
for (int i = 0; i < 100; i++) list.Add(i);
TestSize<List<int>>.SizeOf(list); //-> 717 B

มันใช้ได้กับคลาส:

class twostring
{
    public string a { get; set; }
    public string b { get; set; }
}
TestSize<twostring>.SizeOf(new twostring() { a="0123456789", b="0123456789" } //-> 28 B

นี่คือแนวทางที่ฉันจะทำเช่นกัน คุณสามารถเพิ่มชุดของวัตถุที่พบก่อนหน้านี้ในกราฟเพื่อหลีกเลี่ยง a) การเรียกซ้ำไม่สิ้นสุดและ b) หลีกเลี่ยงการเพิ่มหน่วยความจำเดียวกันซ้ำสองครั้ง
mafu

4

สิ่งนี้เป็นไปไม่ได้ที่จะทำในรันไทม์

มีโปรไฟล์หน่วยความจำหลายแบบที่แสดงขนาดวัตถุ

แก้ไข : คุณสามารถเขียนโปรแกรมที่สองที่กำหนดโปรไฟล์โปรแกรมแรกโดยใช้CLR Profiling APIและสื่อสารกับมันผ่านการรีบูตหรือบางสิ่งบางอย่าง


17
หากไม่สามารถทำได้ในรันไทม์ผู้สร้างโปรไฟล์หน่วยความจำจะให้ข้อมูลได้อย่างไร?
เจนี่

2
โดยใช้ Profiling API อย่างไรก็ตามโปรแกรมไม่สามารถสร้างโปรไฟล์ตัวเองได้
SLaks

น่าสนใจ. จะเป็นอย่างไรถ้าฉันต้องการให้โค้ดจัดการกับเคสเมื่ออ็อบเจ็กต์ใช้หน่วยความจำมากเกินไป
เจนี่

4
ถ้าอย่างนั้นคุณจะต้องจัดการกับซอฟต์แวร์ที่รู้จักตนเองและฉันก็กลัวมาก :-) อย่างจริงจัง "หลักความรับผิดชอบเดียว" - ปล่อยให้โปรแกรมเป็นโปรแกรมปล่อยให้ส่วนอื่น ๆ ของรหัสเฝ้าดูวัตถุที่ใช้หน่วยความจำมากเกินไป
John Saunders

2
@ Janie: คุณจะตั้งสมมติฐานเกี่ยวกับความสำคัญของขนาดและความสัมพันธ์กับประสิทธิภาพ ฉันคิดว่าคุณต้องการเป็นผู้เชี่ยวชาญด้านประสิทธิภาพ CLR ระดับต่ำตัวจริง (ผู้ที่รู้เกี่ยวกับ Profiling API อยู่แล้ว) ก่อนที่คุณจะทำเช่นนั้น มิฉะนั้นคุณอาจนำประสบการณ์ก่อนหน้านี้ไปใช้กับสถานการณ์ที่พวกเขาใช้ไม่ได้
John Saunders

3

ใช้Son Of StrikeObjSizeซึ่งมีคำสั่ง

โปรดทราบว่าหน่วยความจำที่ใช้จริงจะมีขนาดใหญ่กว่าObjSizeรายงานเสมอเนื่องจากหน่วยความจำนั้นsynkblkอยู่ก่อนข้อมูลออบเจ็กต์โดยตรง

อ่านเพิ่มเติมเกี่ยวกับทั้งสองที่นี่MSDN Magazine Issue 2005 พฤษภาคม - เจาะลึก. NET Framework Internals เพื่อดูว่า CLR สร้างออบเจ็กต์รันไทม์อย่างไร


2

AFAIK คุณไม่สามารถทำได้โดยไม่ต้องนับขนาดของสมาชิกแต่ละคนเป็นไบต์ แต่อีกครั้งขนาดของสมาชิก (เช่นองค์ประกอบภายในคอลเลกชัน) จะนับรวมกับขนาดของวัตถุหรือไม่หรือตัวชี้ไปยังสมาชิกนั้นจะนับรวมกับขนาดของวัตถุหรือไม่ ขึ้นอยู่กับว่าคุณกำหนดมันอย่างไร

ฉันเคยเจอสถานการณ์นี้มาก่อนซึ่งฉันต้องการ จำกัด วัตถุในแคชของฉันตามหน่วยความจำที่ใช้ไป

ถ้ามีเคล็ดลับในการทำเช่นนั้นฉันก็ดีใจที่ได้รู้!


2

Marshal.SizeOfสำหรับประเภทค่าคุณสามารถใช้ แน่นอนว่าจะส่งคืนจำนวนไบต์ที่จำเป็นในการจัดโครงสร้างในหน่วยความจำที่ไม่มีการจัดการซึ่งไม่จำเป็นต้องเป็นสิ่งที่ CLR ใช้


SizeOf (Object) อาจไม่พร้อมใช้งานในรุ่นต่อ ๆ ไป ให้ใช้ SizeOf <T> () แทน สำหรับข้อมูลเพิ่มเติมไปที่go.microsoft.com/fwlink/?LinkID=296514
Vinigas

1

คุณสามารถใช้การสะท้อนเพื่อรวบรวมข้อมูลสมาชิกสาธารณะหรือทรัพย์สินทั้งหมด (ตามประเภทของวัตถุ) ไม่มีวิธีใดในการกำหนดขนาดโดยไม่ต้องเดินผ่านข้อมูลแต่ละชิ้นบนวัตถุ


1

สำหรับใครก็ตามที่กำลังมองหาวิธีแก้ปัญหาที่ไม่ต้อง[Serializable]เรียนและผลลัพธ์คือการประมาณแทนที่จะเป็นวิทยาศาสตร์ที่แน่นอน วิธีที่ดีที่สุดที่ฉันสามารถหาได้คือ json serialization ใน memorystream โดยใช้การเข้ารหัส UTF32

private static long? GetSizeOfObjectInBytes(object item)
{
    if (item == null) return 0;
    try
    {
        // hackish solution to get an approximation of the size
        var jsonSerializerSettings = new JsonSerializerSettings
        {
            DateFormatHandling = DateFormatHandling.IsoDateFormat,
            DateTimeZoneHandling = DateTimeZoneHandling.Utc,
            MaxDepth = 10,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };
        var formatter = new JsonMediaTypeFormatter { SerializerSettings = jsonSerializerSettings };
        using (var stream = new MemoryStream()) { 
            formatter.WriteToStream(item.GetType(), item, stream, Encoding.UTF32);
            return stream.Length / 4; // 32 bits per character = 4 bytes per character
        }
    }
    catch (Exception)
    {
        return null;
    }
}

ไม่นี่จะไม่ให้ขนาดที่แน่นอนที่จะใช้ในหน่วยความจำ ดังที่เคยกล่าวไว้ว่าเป็นไปไม่ได้ แต่จะให้การประมาณค่าคร่าวๆ

โปรดทราบว่าสิ่งนี้ค่อนข้างช้า


1

จาก Pavel และ jnm2:

private int DumpApproximateObjectSize(object toWeight)
{
   return Marshal.ReadInt32(toWeight.GetType().TypeHandle.Value, 4);
}

หมายเหตุด้านข้างโปรดใช้ความระมัดระวังเนื่องจากใช้ได้เฉพาะกับวัตถุหน่วยความจำที่อยู่ติดกัน


1

ฉันได้สร้างการทดสอบเกณฑ์มาตรฐานสำหรับคอลเล็กชันต่างๆใน. NET: https://github.com/scholtz/TestDotNetCollectionsMemoryAllocation

ผลลัพธ์เป็นดังนี้สำหรับ. NET Core 2.2 ที่มีวัตถุ 1,000,000 รายการพร้อมคุณสมบัติ 3 รายการที่จัดสรร:

Testing with string: 1234567
Hashtable<TestObject>:                                     184 672 704 B
Hashtable<TestObjectRef>:                                  136 668 560 B
Dictionary<int, TestObject>:                               171 448 160 B
Dictionary<int, TestObjectRef>:                            123 445 472 B
ConcurrentDictionary<int, TestObject>:                     200 020 440 B
ConcurrentDictionary<int, TestObjectRef>:                  152 026 208 B
HashSet<TestObject>:                                       149 893 216 B
HashSet<TestObjectRef>:                                    101 894 384 B
ConcurrentBag<TestObject>:                                 112 783 256 B
ConcurrentBag<TestObjectRef>:                               64 777 632 B
Queue<TestObject>:                                         112 777 736 B
Queue<TestObjectRef>:                                       64 780 680 B
ConcurrentQueue<TestObject>:                               112 784 136 B
ConcurrentQueue<TestObjectRef>:                             64 783 536 B
ConcurrentStack<TestObject>:                               128 005 072 B
ConcurrentStack<TestObjectRef>:                             80 004 632 B

สำหรับการทดสอบความจำฉันพบว่าดีที่สุดที่จะใช้

GC.GetAllocatedBytesForCurrentThread()

1

สำหรับอาร์เรย์ของโครงสร้าง / ค่าฉันมีผลลัพธ์ที่แตกต่างกับ:

first = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0).ToInt64();
second = Marshal.UnsafeAddrOfPinnedArrayElement(array, 1).ToInt64();
arrayElementSize = second - first;

(ตัวอย่างย่อ)

ไม่ว่าจะใช้วิธีใดคุณต้องเข้าใจว่า. Net ทำงานอย่างไรจึงจะตีความผลลัพธ์ได้อย่างถูกต้อง ตัวอย่างเช่นขนาดองค์ประกอบที่ส่งคืนคือขนาดองค์ประกอบ "ชิด" โดยมีช่องว่างภายในบางส่วน ค่าโสหุ้ยและขนาดจึงแตกต่างกันขึ้นอยู่กับการใช้งานประเภท: "boxed" บนฮีป GC บนสแต็กเป็นฟิลด์เป็นองค์ประกอบอาร์เรย์

(ฉันอยากรู้ว่าอะไรจะเป็นผลกระทบต่อหน่วยความจำของการใช้โครงสร้างว่าง "ดัมมี่" (โดยไม่มีฟิลด์ใด ๆ ) เพื่อเลียนแบบอาร์กิวเมนต์ "ทางเลือก" ของยาสามัญทำการทดสอบด้วยเลย์เอาต์ที่แตกต่างกันซึ่งเกี่ยวข้องกับโครงสร้างว่างฉันเห็นว่าโครงสร้างว่างใช้ ( อย่างน้อย) 1 ไบต์ต่อองค์ประกอบฉันจำไม่ได้ว่าเป็นเพราะ. Net ต้องการที่อยู่ที่แตกต่างกันสำหรับแต่ละฟิลด์ซึ่งจะใช้ไม่ได้หากฟิลด์ว่างเปล่า / ขนาด 0)


0

วิธีที่ง่ายที่สุดคือ: int size = *((int*)type.TypeHandle.Value + 1)

ฉันรู้ว่านี่เป็นรายละเอียดการใช้งาน แต่ GC ต้องอาศัยมันและต้องใกล้เคียงกับจุดเริ่มต้นของ methodtable เพื่อประสิทธิภาพรวมถึงการพิจารณาว่า GC code complex จะไม่มีใครกล้าเปลี่ยนแปลงในอนาคต ในความเป็นจริงมันใช้ได้กับ. net framework + .net core ทุกเวอร์ชันรอง / หลัก ๆ (ปัจจุบันไม่สามารถที่จะทดสอบ 1.0)
หากคุณต้องการวิธีที่เชื่อถือได้มากขึ้นปล่อย struct ในแบบไดนามิกประกอบกับ[StructLayout(LayoutKind.Auto)]มีเขตข้อมูลเดียวกันในลำดับเดียวกันใช้ขนาดของมันกับsizeofคำแนะนำ IL คุณอาจต้องการปล่อยวิธีการคงที่ภายในโครงสร้างซึ่งจะส่งคืนค่านี้ จากนั้นเพิ่ม 2 * IntPtr.Size สำหรับส่วนหัวของวัตถุ สิ่งนี้ควรให้คุณค่าที่แน่นอน
แต่ถ้าคลาสของคุณมาจากคลาสอื่นคุณต้องหาแต่ละขนาดของคลาสพื้นฐานแยกจากกันและเพิ่ม + 2 * Inptr.Size อีกครั้งสำหรับส่วนหัว คุณสามารถทำได้โดยรับฟิลด์ที่มีBindingFlags.DeclaredOnlyธง
อาร์เรย์และสตริงจะเพิ่มขนาดความยาว * ขนาดองค์ประกอบ สำหรับขนาดสะสมของวัตถุ aggreagate คุณต้องใช้โซลูชันที่ซับซ้อนมากขึ้นซึ่งเกี่ยวข้องกับการเยี่ยมชมทุกฟิลด์และตรวจสอบเนื้อหา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.