变量内存分配知多少

  繁忙的工做总容易让咱们忽视最基础的知识,手里的活停一停,下楼呼吸下新鲜空气(北京的朋友抱歉了),让大脑切换下进程。闭包

  回想工做中咱们所遇到的难点,嗯,好多都是咱们对基础知识了解得不够透彻,或者说只知道了表层的东西。而每每咱们老是被这些表层东西所欺骗了,最后等待咱们的就是bug量增多,性能低下,运行不稳定,维护成本剧增,客户满意度降低,更严重的即可能致使项目进入恶性循环。可想而知,咱们所面临的挑战是多么艰巨。函数

  言归正传,本节咱们主要讲的内容是.Net中变量内存分配,是的,就讲这么简单的知识。性能

1、咱们先看下类的成员变量:优化

public class Customerthis

{spa

        int customerId;3d

        string customerName;对象

}blog

 

public class Customer进程

{

        int customerId = 0;

        string customerName = null;

}

  乍看之下,咱们会以为第二种写法更加合情合理,但咱们的编译器没有那么智能。他总会首先帮咱们将成员变量赋予一个初始值,当咱们人为赋予初始值的时候,编译器会在调用默认构造函数以前用咱们赋予的初始化值替换他默认初始化的值。也就是除非咱们初始化的数据是业务相关数据,不然咱们赋默认值则给JIT增长了负担。

2、静态变量:

  当咱们增长个CustomerCount int类型静态变量,并赋予初始值0时,这个时候咱们会发现,编译器默认给咱们建立了一个静态构造函数,并在静态构造函数中替换掉编译器默认初始化的值。若是咱们不人为初始化呢,其实编译器还会自动为咱们提供一个静态的构造函数,除非是咱们的类没有静态变量。静态构造函数只会执行一次

3、常量:

  一、咱们知道静态常量无需分配内存的,并且必须定义的时候就得赋初始化值,这样的优势咱们也不难发现他会带来潜伏的bug,当他的引用(实际上是那个常量值)分布到不一样的程序集中时,若是后期因为业务变化须要改变常量值时,项目必须总体从新编译一次,不然其余引用的程序集常量还保持原来值。能够看到,这给咱们维护带来了不便。

  二、因为静态常量带来的不便,因此这个时候动态常量便应运而生了,动态常量须要分配内存的,其必须在声明或在构造函数中赋初始化值,若是不人为赋值,编译器会初始化默认值的,但这样的常量是毫无心义的。

4、局部变量:

  咱们都很清楚,C#中访问局部变量的以前,咱们必须人为为他赋初值,若是没有赋值,则编译就不会经过。其实这个时候,编译器是很聪明的,咱们声明了一个局部变量,但不给他赋值,咱们要这个局部变量干吗呢(闭包状况不在这个范围)?他并非类成员变量,能够共享。反过来想想,若是编译器也为局部变量赋初值,那么JIT的负担得多么重。因此默认状况下,C#是不会初始化局部变量的。

下面咱们来看看局部变量内存分配的状况:

public class Customer

{

        public Customer GetCustomer()

        {

            int customerId = 4;

            Customer customer = GetCustomerById(customerId);

            return customer;

        }

 

        private Customer GetCustomerById(int id)

        {

            Customer customer = new Customer();

            return customer;

        }

}

好,具体状况咱们来看图:

说明:①②给局部变量customerId赋值。

③④将this和customerId值压入堆栈,准备调用GetCustomerById方法。

说明:⑤⑥调用GetCustomerById方法

⑦⑧在托管堆上建立Customer对象,并给局部变量customer赋值

说明:⑨⑩给返回值returnObj赋值,returnObj是编译器建立的临时存放返回值得局部变量

⑪将返回值的内容压入堆栈

说明:⑫GetCustomerById方法执行完毕,将返回值传递到调用方维护的堆栈里。此时GetCustomerById局部变量都被堆栈弹出,这部份内存自动收回。

⑬给局部变量customer赋值

说明:⑭⑮给局部变量returnObj赋值

⑯将返回值压入堆栈中

  上图,只是为了形象说明局部变量内存分配状况,并非最终本地代码执行时内存状况,JIT还会为咱们作不少优化,并且局部变量表没有体现到堆栈中。

 

  从上图中,咱们能够知道,局部变量中值类型的值存放到堆栈中(并非全部值类型都存放在堆栈区,有例外状况,好比闭包和yield的状况就比较特殊,编译器会提高局部变量的),而引用类型则是在托管堆中开辟内存存放引用类型对象,其对象引用则是存放到堆栈中。

    ——Aaron.Pan

相关文章
相关标签/搜索