对象被定义后系统会给它分配一定的内存空间
类的实例也占用内存空间
new关键字是对一个对象的实例化,听人说就是给对象分配一定的内在空间
那,为实例化对象时又要重复给它分配内存呢?或者说对象所占用的内在空间和实例占用的内在空间有什么区别?
一头雾水呀,请各位大侠帮忙解释一下了,谢谢哈!

解决方案 »

  1.   

    class1 cls;//这样是不分配内存的
    cls = new class1();//这个时候分配内存
    也就是说在new的时候分配内存
      

  2.   

    classA cls;(c#中仅仅是个申明,这和C++不同)
    cls = new classA()
      

  3.   

    new的时候是创建分配空间,classA cls;是一个申明应用不分配空间
      

  4.   

    声明时是在栈里写了个名字, new以后, 才是在托管堆里分配了空间, 当然这个空间有可能为空. 将栈里的名字指向堆里的空间地址
      

  5.   

    CLR会把所有的引用类型的对象分配到一个托管堆(managed heap)的地方。应用程序初始化后,CLR会保留(reserve)一块连续空间,起初这块空间并不对应实际的物理内存,这块地址空间就是一个托管堆。托管堆上维护着一个指针,这个指针用来标记下一个对象存储的起始地址。 具体的分配过程是:先计算类型实例所需的字节总数,再在这个数目上加两个附加字段所需要的字节数,这两个对象是一个方法表指针 和 一个,CLR会判断这个堆也就是所谓的保留空间是否有足够的空间来承接这个对象实例,如果可以则只需将托管段维护的那个指针越过这个对象所占的空间,否则,要提交物理内存。也就是说托管堆里面的内存分配是连续的,而这样的特性使垃圾回收环境拥有较小的应用程序工作集,加快了速度,使性能有所提高。 显然CLR工作作了一个假设,就是应用程序的地址空间和存储空间的无穷大性,但是这是不可能的,而之所以可以这样假设就是因为有了.net的 垃圾回收器。 在给类型实例对象分配空间的时候,当托管堆上维护的指针在以分配空间的基础上再往后跨一个要分配对象空间,如果超出了托管堆的地址空间范围,则说明该托管堆已经占用完,需要垃圾回收! 接下来是垃圾回收算法!
    垃圾回收器要回收的目标是所有应用程序不再使用的对象所占用的内存,但是它怎么知道那些对象是否已经不再使用了哪? .net在应用程序里面定义了一个根(root)的概念,一个跟就是一个存储位置,其实就是一个引用类型的内存指针,这样的指针指向一个托管堆的对象或者null,全局引用类型变量、静态引用类型变量、一个线程堆栈上所有引用类型的本地变量或者参数变量都被认为是根(一个方法内的指向引用类型对象的cpu寄存器也是根,这样的寄存器是什么咚咚?)。 JIT编译器编译一个方法的中间语言代码的时候,除了产生CPU的本地代码外,还会创建一个内部表,该表中标识一个方法的本地指令的字节偏移范围和一组包含根的内存地址(CPU寄存器)。垃圾回收器会遍历线程的调用堆栈,通过检测其中每一个方法的内部表来确定调用方法的根;另外,GC会利用一些手段来获得全局应用类型变量和静态引用类型变量。GC遍历线程的调用堆,将直接可达的根构造一个可达对象图,我们会发现会有根在应用另外的根,在所达根不重复的前提下,最终构造出完全可达根图,于是在这个堆栈上不可达的对象便是GC收集的目标!还没完,如果找到一个较大的连续空间,GC会把非垃圾对象搬移过来,并且GC会自动矫正他们的位置。 可见垃圾回收对程序性能会有影响,但是我们需要明确的有几点:只有第0代对象充满的时候,才会回收;CLR提供特殊的优化设计来提高垃圾回收的性能。 到此为止,我们就明白在.net程序中为什么不再出现资源泄露和对象状态不稳定的bug了!