• .net GC内存管理 前置篇 (数据类型)


    内存栈和内存Stack vs Heap

    栈Stack :
    1)是一个内存数组,类似子弹弹夹一样先进后出的结构体,意味着只能从顶部添加或从顶部删除;
    2)内存分配是静态的,变量无法调整大小;
    3)访问速度相对快;
    3)同时只能由一个执行线程使用;
    5)一旦脱离作用域,立刻被清除;

    堆Heap :
    1)是一块内存,在其中分配了块以存储某些类型的数据对象;
    2)内存分配是动态的,变量可以调整大小;
    3)访问速度相对慢;
    4)同时能被多个线程使用;
    5)托管堆由GC来清除,非托管堆由个人自行清除;


    值类型

    值类型被创建后,会在栈Stack上分配一个固定的空间,存储创建的实际数据
    当值类型超出它所存在的作用域时,会在栈上被立刻清除;

    引用类型

    引用类型被创建后,会在堆Heap上分配一个非固定的空间,存储创建的实际数据;同时在栈Stack上分配一个固定的空间,存储的数据为一个地址,而这个地址代表了刚刚在堆Heap上创建的实际数据的位置;
    当引用类型的实例,超出它所存在的作用域时,会在栈上被立刻清除;而在堆上的数据会等待下一次GC回收来清除(如果它可被回收,具体见上一篇博客);

    C# 数据类型(值类型,基类为System.ValueType)

    • bool :布尔
    • char :字符
    • decimal :高精度浮点数
    • double :双精度浮点数
    • float :单精度浮点数
    • int :整形
    • long :长整形
    • enum :枚举
    • struct :结构体
      没有 == 操作符,需要自己重写
    • keyvaluepair :键值对
      Dictionary的子元素,通常foreach Dictionary时候的item,因为它继承自结构体struct,所以没有 == 操作符,需要自己重写,虽然Dictionary是引用类型,但是keyvaluepair却是值类型

     ps: 这里只列了常用部分的数据类型,其他相近类似的也是属于值类型;

    C# 数据类型(引用类型,基类为System.object)

    • class :类
    • interface : 接口
    • delegate : 委托
    • object :基类
    • string :字符串
      被当做值类型来使用的引用类型,string的几乎所有操作符和方法都是通过堆中实际值来计算,而不是栈中的地址;
    • string[] :
      字符串数据,需在初始化的时候就定义好长度;
    • ArrayList :
      类型集合,长度可以伸缩,可以添加任何类型的元素,所以没有类型安全,实际是以object来实现,这就意味着添加元素的时候,会把元素放进object中俗称装箱,拿出时再拆箱成具体类型;
    • List<T>:
      ArrayList的泛型版本,节省了装箱拆箱的性能,对类型有约束,所以是类型安全;
    • HashTable :
      key value集合,长度可以伸缩,可以添加任何类型的元素,所以没有类型安全,实际是以object来实现,同样需要装箱拆箱(也可以说是ArrayList的key value版本)(据说有提供线程安全的方法Synchronized,但还是建议用专门提供线程安全的Concurrent集合)
    • Dictionary :
      HashTable 的泛型版本,节省了装箱拆箱的性能,对类型有约束,所以是类型安全;(也可以说是List<T>的key value版本)
    • ConcurrentBag :
      线程安全版本的List<T>
    • ConcurrentDictionary :
      线程安全版本的Dictionary <T>

     ps: 这里只列了常用部分的数据类型,其他相近类似的也是属于引用类型;

    Q&A

    • Q:引用类型是分配在堆里的吗?
      A:引用类型是在堆里存储实际数据,然后在栈中存储指向堆里实际数据的地址;引用类型的Operator(==, ! =, =等)和 方法(add,remove等)均是操作的地址,重写过该方法的除外;
    • Q:Null是什么数据类型?Nullable是什么数据类型
    • A:Null没有类型,对于引用类型来说,赋值null指的是空引用,对于值类型来说,一般是不能赋值null的,除非是Nullable比如int?;Nullable实际是Nullable<T>的结构体struct,一种实现可赋值空的把戏;
    • Q: 所有的类型都继承自System.object,难道System.ValueType不是吗?如果是的话,继承自System.ValueType的类型为什么是值类型而不是引用类型?
      A:System.ValueType是继承自System.object,但是CLR对继承自System.ValueType的子类做了特殊处理,使其拥有值类型的特性。
    • Q: == vs equals
      A:对于引用类型来说,==比较是存在栈中的引用地址,equals则比较的是存在堆中的实际对象值;
      对于值类型来说,==和equals都是比较的是存在栈中的实际值,但是 == 会尝试把左右两边的比较值做类型转换再比较,而equals不会;
      但是有一些例外,比如string是引用类型,==是被重写过的,实际用的是equals,所以string永远比较是实际值,而class使用equals时,即使属性值都一样也是false,因为class并没有重写equals,所有调的是父类的equals方法,          但是父类并不知道class中有哪些属性,所以也是false。
      鉴于==和equals都是可以被覆盖,如果只是单纯想比较引用地址是否一样,可以使用ReferenceEquals,该方法不会被覆盖;
      string s1 = "test";
      string s2 = "test";
      string s3 = "test1".Substring(0, 4);
      object s4 = s3;
      Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
      Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
      Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));
      

      The output is:

      True True True
      False True True
      False False True
    • Q:值类型与引用类型在代码上最大的区别?
      A:当引用类型实例都是同一地址时,改变被引用对象的值时,所有实例都会改变,除非是通过深拷贝的方式来改变;当引用类型和值类型被当做参数传入另一个方法返回时,引用类型实例会自动改变,而值类型要通过ref、out的方式来返回才可以,这是因为引用类型传递是地址,而值类型传递的是值的复制;
  • 相关阅读:
    Java IO中转换流的作用
    Java IO流学习总结五:转换流-InputStreamReader、OutputStreamWriter
    Java IO流学习总结四:缓冲流-BufferedReader、BufferedWriter
    Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream
    Java IO流学习总结二:File
    Java IO流学习总结一:输入输出流
    Tomcat安装
    nginx配置文件详解(包括动静分离、负载均衡配置以及优化)
    LVS+keepalived配置文件详解
    LVS+keepalived均衡nginx配置
  • 原文地址:https://www.cnblogs.com/willardzmh/p/13381341.html
Copyright © 2020-2023  润新知