美文网首页
C#中数据到底存在堆上还是栈上

C#中数据到底存在堆上还是栈上

作者: 小血Blood | 来源:发表于2018-06-13 22:40 被阅读0次

    C#的栈与堆

    首先复习一下值类型与引用类型

    1. 值类型与引用类型

    值类型:基本数据类型([int,long,float,char,bool]:System.ValueType,enum,struct)
    引用类型:类(所有class),string,接口,数组

    2. 栈与堆

    局部变量,参数,调用现场存在栈中,一个线程的栈默认只有1M,栈要求先进后出的原则。
    static的变量在静态存储区。
    const的常量在常量存储区。
    引用类型对象中的数据存放在堆内存中,由GC系统回收。

    3. 数据到底储存在哪里?

    引用类型的对象总是放在堆上。
    值类型和指针总是放在它们被声明的地方。

    如何理解呢?
    其实很简单,看代码:

    public class C
    {
      //在类中被声明[跟随此类储存在堆中]
      int i = 0;//值类型
      //在类中被声明[跟随此类储存在堆中]
      S s = new S();//值类型
      //c:对象的引用[跟随此类储存在堆中]
      //new C():引用类型的对象永远储存在堆中
      C c = new C();//引用类型
    }
    public struct S
    {
      int i;//值类型
      S s;//值类型
      C c;//引用类型
    }
    
    //argI:值类型,在参数中被声明[储存在栈上]
    //argS:值类型,在参数中被声明[储存在栈上,且其中的值类型变量i和s都跟随他储存在栈上,而引用类型c的引用也跟随他储存在栈上,而c的对象储存在堆上]
    //argC:引用类型[对象的引用储存在栈上,而对象储存在堆上]
    void Main(int argI,S argS,C argC)
    {
      //如果argI,argS,argC定义在局部变量中也和定义在参数中类似
      int tmpI = 0;
      S tmpS = new S();
      C tmpC = new C();
    }
    

    4. string是一种特殊的引用类型,以及为什么要使用StringBuilder

    string直接继承自System.Object,这使得它成为一个引用类型,也就是说,C#中string是存在堆上的。

    引用一段说明:

    string str1 = "string"; 
    string str2 = "string"; 
    Console.WriteLine(string.ReferenceEquals(str1, str2));
    

    既然String类型是引用类型,那么代码一输出的应该是False,然而事实上代码一输出时的是True。
      其实这是String类型的自动优化功能。str1,str2引用同一对象,节省内存,并不会为str2单独开辟内存空>间。CLR使用了一种叫字符串驻留的技术,当CLR初始化时,会创建一个内部的散列表,其中的键为字符串,>值为指向托管堆中字符串的引用。刚开始,散列表为空,JIT编译器编译方法时,会在散列表中查找每一个文本常量字符串,首先会查找"abc"字符串,并且因为没有找到,编译器会在托管堆中构造一个新的指向"abc"的>String对象引用,然后将"abc"字符串和指向该对象的引用添加到散列表中。接着,在散列表中查找第二个"abc",这一次由于找到了该字符串,指向同一个String对象的引用会被保存在变量str2中,到此str1和str2指向了同一个引用,所以string.ReferenceEquals(str1, str2)就会返回true了。
      另外,C#中是不允许用new操作符创建String对象的,编译器会报错。

    MSDN:字符串对象是不可变的,即它们一旦创建就无法更改。对字符串进行操作的方法实际上返回的是新的字符串对象。

    String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 System.Text.StringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。

    相关文章

      网友评论

          本文标题:C#中数据到底存在堆上还是栈上

          本文链接:https://www.haomeiwen.com/subject/gheseftx.html