这个问题是由
http://community.csdn.net/Expert/topic/5633/5633221.xml?temp=.3441278
这个帖子想到的。object o1 = new object();
实例化后的o1在托管堆中占用了多少个字节,每个字节里面代表的意义是什么?做程序测的结果是占用12字节,有趣的是,object本身有4个方法,12个字节是怎么存下4个方法的指针的,这还不算同步块索引和类型指针。ms是怎么实现它的呢?测试程序如下:
    class Class1
    {
        static void Main(string[] args)
        {
            int b = 2;
            object o1 = new object();
            object o2 = new object();
            unsafe
            {
                int* p = &b;
                Console.WriteLine("&o1 = {0:X}", *(p - 1));
                Console.WriteLine("&o2 = {0:X}, o1 size = {1}", *(p - 2), *(p - 2) - *(p - 1));
            }
            Console.ReadKey();
        }
    }

解决方案 »

  1.   

    int 和 object 一个是值类型,一个是引用类型,根本不在一起,且托管代码还要由.net框架再编译,lz的代码说明不了问题
      

  2.   

    因为微软对于.net底层实现是不公开的,我对此也没有研究过,只能猜测
    int b=1;
    object o1 ..
    object o2 .......
    托管对象是引用类型
    就算如lz所说
    *(p - 2) - *(p - 1) =12 这里也只是3个指针的长度,而非object 的长度
      

  3.   

    // C#
    object o1 = new object(); // 对象变量,实际上 o1 存储的只是一个指向 object 实例的引用
    object o2 = new object();应该等价于// C++
    object* o1 = new object(); // 指针变量, 存储空间开辟在 堆区
    object* o2 = new object();而不是
    // C++
    object o1; // 对象变量,存储空间开辟在 栈区 (考虑局部变量,不考虑全局变量)
    object o2; // 对象变量
    所以......加上,hdt(倦怠) 的解释,应该可以从 宏观 上理解了至于,底层具体如何实现的,只有垂寻 Anders Hejlsberg,Don Box 他们了不管,怎么说,这确实是一个相当有意思的问题
      

  4.   

    我详细解释下,栈上分配了int b,指针o1,指针o2,这三个是连续的,最少在我测试的过程中都是连续的。
    指针大小都为4字节,无论什么指针,那么b的指针p,在栈上移动4字节(int型移动4)是(p-1),正好可以移动到o1在栈上的指针位置,这里主要是因为int的占用和指针占用大小一样,那么*(p-1)正好是指针o1指向托管堆的地址值,**(p-1)才是o1在托管堆的内容,如果看原贴的话会清楚很多,(p-1)是作为二重指针来用的。
      

  5.   

    占据的存储空间不一定是连续的,但是在示例的程序中,基本不太可能不连续,因为在分配之前没有存在任何的对象回收,而且每个对象的大小都很小。
        public class Class2
        {
            private int a;
            public int c;  
            public int d; 
        }    class Class1
        {
            static void Main(string[] args)
            {
                int b = 2;
                Class2 o1 = new Class2();
                Class2 o2 = new Class2();
                unsafe
                {
                    int* p = &b;
                    Console.WriteLine("&o1 = {0:X}", *(p - 1));
                    Console.WriteLine("&o2 = {0:X}, o1 size = {1}", *(p - 2), *(p - 2) - *(p - 1));
                }
                Console.ReadKey();
            }
        }借用原作者的意思,直接这样输出结果20,去掉private int a;这句就变为16,再去掉        public int c;变12,最后把类清空了什么也没有,还是12。这说明内存地址还是连续的,不过在大点的程序中,连续的情况就难说了。
      

  6.   

    占据的存储空间不一定是连续的,但是在示例的程序中,基本不太可能不连续,因为在分配之前没有存在任何的对象回收,而且每个对象的大小都很小。
        public class Class2
        {
            private int a;
            public int c;  
            public int d; 
        }    class Class1
        {
            static void Main(string[] args)
            {
                int b = 2;
                Class2 o1 = new Class2();
                Class2 o2 = new Class2();
                unsafe
                {
                    int* p = &b;
                    Console.WriteLine("&o1 = {0:X}", *(p - 1));
                    Console.WriteLine("&o2 = {0:X}, o1 size = {1}", *(p - 2), *(p - 2) - *(p - 1));
                }
                Console.ReadKey();
            }
        }借用原作者的意思,直接这样输出结果20,去掉private int a;这句就变为16,再去掉        public int c;变12,最后把类清空了什么也没有,还是12。这说明内存地址还是连续的,不过在大点的程序中,连续的情况就难说了。