基本

□ 哪些属于引用类型

类(object,string),接口、数组、委托

□ 引用类型分配在哪里

● 引用类型变量位于线程栈。
● 引用类型实例分配在托管堆上。
● 当引用类型实例的大小小于85000bytes,被分配在GC堆上,当大于或等于85000bytes,被分配在LOH(Large Object Heap)上。

□ 变量(Variable),对象(Object),实例(Instance)

变量:
变量分配在线程栈上。
变量可以是值类型,也可以是引用类型。
当变量是引用类型时,包含了对对象的引用(内存地址),也叫做"对象引用"。

对象:
对类、接口、委托和数组等的一个抽象描述。

实例:
在堆上创建的对象,称为对象实例。

□ 引用类型没有new意味着什么?

Object a = null;
Console.WriteLine(a.ToString());
运行报错"未将对象引用设置到对象实例"。
意思是,在线程栈上创建的变量a没有指向到堆上的对象实例。

□ 托管堆上的垃圾回收

GC会遍历所有托管堆上的对象,按照一定的递归遍历算法,对那些没有被引用的不可访问对象实施回收。

new的背后发生了什么

展开 class Program
{
static void Main(string[] args)
{
Person p;
p = new Person(20);
}
} public class Person
{
public int _age; public Person(int age)
{
_age = age;
} public Person()
{ }
}

另外,引用类型的值,比如这里的引用类型Person中的值_age也被分配在托管堆上。

线程栈上的2个变量引用同一个对象实例的内存地址

线程栈上的2个变量引用同一个对象实例的内存地址,改变其中一个变量的值会影响到另外一个变量。

展开    class Program
{
static void Main(string[] args)
{
Person p1 = new Person(20);
Person p2 = p1;
Console.WriteLine("没有改变时p2的年龄是:" + p2._age + "岁");
p1._age = 18;
Console.WriteLine("改变p1的值,p2的年龄也被改变了,现在是:" + p2._age + "岁,真好,年轻了!");
Console.ReadKey();
}
} public class Person
{
public int _age; public Person(int age)
{
_age = age;
} public Person()
{ }
}

string类型是特殊的引用类型

□ 特殊性体现在

从应用角度体现了值类型语义,从内存角度实现为引用类型存储,位于托管堆。

□ 什么是string
可以看作是char的集合char[]

□ string创建与实例化

string str = "Hello";

以下错误
String str = new String("Hello");
因为System.String没有提供此构造函数

以下可以
Char[] cs = {'a', 'b','c'};
String strArr = new String(cs);
但很少使用这种方式。

□ 字符串的恒定性Immutability

是指字符串一经创建,就不可改变。
字符串一旦创建,在托管堆上分配一块连续的内存空间。

恒定性的好处:
对String对象的任意操作,不会改变原字符串。
操作字符串不会出现线程同步的问题。
成就了字符串驻留。

恒定性的不足:
因为恒定性,对字符串的任何操作,比如字符串比较,字符串链接,字符串格式化等都会创建新的字符串,这样造成内存与性能的双重损耗。如下:

public static void Main() 
{ 
    string str = "This is a test about immuntablility of string type."; 
    Console.WriteLine(str.Inseert(0,"Hi").Substring(19).ToUpper()); 
    Console.WriteLine(str); 
} 

由于Insert,Substring,ToUpper这些方法,都会创建出新的临时字符串,而这些新的字符串不被其他代码引用的时候,就会被垃圾回收,造成性能上的损失。

恒定性的前提,String为密封类:

public sealed class String:IComparable, ICloneable,IConvertible,IComparable<string>,IEnumerable<char>,IEnumerable,IEquatable<string>

□ 字符串驻留String Interning

MSDN对于字符驻留的定义:公共语言运行库通过维护一个哈希表(Hash Table)来存放字符串,该表成为拘留池,也叫驻留池。

字符串驻留弥补了恒定性的不足:
对于相同的字符串,CLR不会不会为其分配内存空间,而是共享同一内存。
CLR内部维护了一个哈希表HashTable来管理其创建的大部分String对象。key是string本身,value是string对应的内存地址。

驻留的2个静态方法:
public static string Intern(string str);
当str位于作为key位于CLR的驻留池时,返回对str的引用,否则将str字符串添加到hash table中,作为key,并返回引用。

public static string IsInterned(string str);
当str位于作为key位于CLR的驻留池时,返回对str的引用,否则返回null引用,也不添加到hash table中。

□ 字符串驻留是进程级的

可以跨应用程序域AppDomain而存在,驻留池在CLR加载时创建,分配在System Domain中,被进程所有AppDomain所共享,其生命周期不受GC控制。

例子1:

        static void Main(string[] args) 
        { 
            string strA = "ab"; 
            string strB = "ab"; 
            Console.WriteLine(ReferenceEquals(strA,strB)); 
            string strC = "a"; 
            string strD = strC + "b"; 
            Console.WriteLine(ReferenceEquals(strA, strD)); 
            strD = String.Intern(strD); 
            Console.WriteLine(ReferenceEquals(strA,strD)); 
            Console.ReadKey(); 
        }

返回:
true
false
true

分析:
● strA与strB内容相同,在hash table中的key相同,对应了一样的引用地址,所以返回true。
● strD的内容虽然与strA相同,但由于是动态生成的,不会把hash table中key为ab的引用地址赋值给strD,所以strA与strD引用地址不一样,返回false。
● strD = String.Intern(strD);手动对strD实施驻留,并发现hash table中已经有了ab这个key,就把对应的引用地址赋值给了strD,这样,strA与strD引用地址相同,返回true。

例子2:

        static void Main(string[] args) 
        { 
            string s1 = "abc"; 
            string s2 = "ab"; 
            string s3 = s2 + "c"; 
            Console.WriteLine(string.IsInterned(s3) ?? "null"); 
            Console.WriteLine(ReferenceEquals(s1,s3)); 
            Console.ReadKey(); 
        }

返回:
abc
false

分析:
● string.IsInterned(s3)对s3进行手动驻留,发现hash table中abc这个key,于是,就返回abc的引用地址。但并没有把引用地址赋值给s3。
● s1和s3的引用地址还是不一样,返回false。

例子3:

        static void Main(string[] args) 
        { 
            string strA = "abcdef"; 
            string strC = "abc"; 
            string strD = strC + "def"; 
            Console.WriteLine(ReferenceEquals(strA,strD)); 
            string StrE = "abc" + "def"; 
            Console.WriteLine(ReferenceEquals(strA,StrE)); 
            Console.ReadKey(); 
        }

返回:
False,       
true

分析:
● 因为strD = strC + "def"中strD的内容虽然与strA想同,但因为是动态生成的,不会被添加到hash table中,所以引用地址不一样,返回false。
●  "abc"+"def在IL中呈现为abcdef,不是动态生成的,并且发现hash table中已经有了abcdef这个key,于是就把对应的引用地址赋值给了strE,这样strA和StrE就有了相同的引用地址,返回true。如图:

例子4:

        static void Main(string[] args) 
        { 
            string s = "abc"; 
            //IsInterned()获取字符串变量的引用 
            Console.WriteLine(string.IsInterned(s) ?? "null"); 
            Console.ReadKey(); 
        }

返回"abc"。
分析:通过string s = "abc"使得hash table中有abc这个key,当进行string.IsInterned(s)手动驻留判断的时候,发现有abc这个key,就把对应的引用地址返回。

例子5:

    class Program 
    { 
        static void Main(string[] args) 
        { 
            string s = "ab"; 
            s += "c"; 
            //IsInterned()获取字符串变量的引用 
            Console.WriteLine(string.IsInterned(s) ?? "null"); 
            Console.ReadKey(); 
        } 
    }

返回null
分析:通过string s = "ab";使得hash table中有了ab这个key,s += "c"是动态拼接,不会把abc放到hashtable中,所以当通过string.IsInterned(s)手动驻留判断的时候,发现没有abc这个key,就返回null。

参考资料
《.NET之美》--张子阳,感谢写了这么好的书!
《你必须知道的.NET》--王涛worktile创始人,感谢!

05引用类型以及特殊引用类型string的更多相关文章

  1. 值类型与引用类型(特殊的string) Typeof和GetType() 静态和非静态使用 参数传递 相关知识

    学习大神博客链接: http://www.cnblogs.com/zhili/category/421637.html 一 值类型与引用类型 需要注意的string 是特殊类型的引用类型. 使用方法: ...

  2. js常用API 数据类型 基本类型,基本包装类型,引用类型 Object String Array Boolean Number Date Math

    数据类型 变量.作用域及内存 基础类型(primitive value):Undefined.Null.Boolean.Number和String.这些类型在内存中分别占用固定大小的空间,他们的值保存 ...

  3. 转:C# String为值类型还是引用类型

    关于String为值类型还是引用类型的讨论一直没有平息,最近一直在研究性能方面的问题,今天再次将此问题进行一次明确.希望能给大家带来点帮助,如果有错误请指出. 来看下面例子: //值类型 int a ...

  4. 图解C#的值类型,引用类型,栈,堆,ref,out

    C# 的类型系统可分为两种类型,一是值类型,一是引用类型,这个每个C#程序员都了解.还有托管堆,栈,ref,out等等概念也是每个C#程序员都会接触到的概念,也是C#程序员面试经常考到的知识,随便搜搜 ...

  5. .NET面试题解析(01)-值类型与引用类型

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 常见面试题目: 1. 值类型和引用类型的区别? 2. 结构和类的区别? 3. delegate是引用类型还 ...

  6. 30天C#基础巩固-----值类型/引用类型,泛型,空合并操作符(??),匿名方法

    一:值类型/引用类型的区别      值类型主要包括简单类型,枚举类型,和结构体类型等,值类型的实例通常被分配在线程堆栈上面变量保存的内容是实例数据本身.引用类型被分配在托管堆上,变量保存的是地址.引 ...

  7. JavaScript高级程序设计学习笔记--引用类型

    Object类型 对象字面量表示法: var person={ name:"Nicholas", age:29, 5:true }; 这人例子会创建一个对象,包含三个属性:name ...

  8. js-变量、作用域和内存问题,引用类型

    变量.作用域和内存问题 1.变量可能包含两种不同数据类型的值:基本类型值以及引用类型值:引用类型值保存的是内存中的对象 2.对象是按值传递的, function setName(obj){ obj.n ...

  9. 深入解析js中基本数据类型与引用类型,函数参数传递的区别

    ECMAScript的数据有两种类型:基本类型值和引用类型值,基本类型指的是简单的数据段,引用类型指的是可能由多个值构成的对象. Undefined.Null.Boolean.Number和Strin ...

随机推荐

  1. POJ 3376 Finding Palindromes(manacher求前后缀回文串+trie)

    题目链接:http://poj.org/problem?id=3376 题目大意:给你n个字符串,这n个字符串可以两两组合形成n*n个字符串,求这些字符串中有几个是回文串. 解题思路:思路参考了这里: ...

  2. Luogu P1750 【出栈序列】

    一眼(万年)贪心minn设小调不出来祭 首先要保证更靠前的输出更小那么容易想到,对于之后可能入栈的元素(即栈的剩余空间仍能装下的所有元素),我们可以取其中的最小值minn,和栈顶元素$top$比较,如 ...

  3. 四B象限图

  4. codis+redis 集群搭建管理

    Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使 ...

  5. Hive(八)Hive的Shell操作与压缩存储

    一.Hive的命令行 1.Hive支持的一些命令 Command Description quit Use quit or exit to leave the interactive shell. s ...

  6. Asp.Net Core2.0允许跨域请求设置

    1.services /// <summary> /// /// </summary> /// <param name="services">& ...

  7. 【Java】 foreach对数组赋值问题

    今天写代码时发现了如下问题: public class Test { public static void main(String[] args) { int[] arr= new int[5]; f ...

  8. JS图片滚动代码(无缝、平滑)

    非常平滑的JS图片滚动特效代码,无缝循环,速度可自定义,鼠标悬停时停止.它的特点是JS和图片地址分离,这样做你就经易的从数据库动态调用每张图片的地址,方便控制,因此它非常的应用. <!DOCTY ...

  9. Ionic入门七:ionic tab(选项卡)

    ionic tab(选项卡) 是水平排列的按钮或者链接,用以页面间导航的切换.它可以包含文字和图标的组合,是一种移动设备上流行的导航方法. 1.基本用法 以下选项卡容器使用了 tabs 类,每个选项卡 ...

  10. 洛谷P1527 [国家集训队] 矩阵乘法 [整体二分,二维树状数组]

    题目传送门 矩阵乘法 题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入输出格式 输入格式: 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共N* ...