C#经典面试题:执行string abc=“aaa“+“bbb“+“ccc“共分配了多少内存?

C#经典面试题:执行string abc="aaa"+"bbb"+"ccc"共分配了多少内存?

这是一个经典的基础知识题目,它涉及了字符串的类型、堆栈和堆的内存分配机制,因此被很多人拿来考核开发者的基础知识功底。

首先,我们都知道,判断值类型的标准是查看该类型是否会继承自System.ValueType,通过查看和分析,string直接继承于System.Object,因此string是引用类型,其内存分配会遵照引用类型的规范,也就是说如下的代码将会在堆栈上分配一块存储引用的内存,然后再在堆上分配一块存储字符串实例对象的内存。

  string a = "edc";

现在再来看看string abc="aaa"+"bbb"+"ccc",按照常规的思路,字符串具有不可变性,大部分人会认为这里的表达式会涉及很多临时变量的生成,可能C#编译器会先执行"aaa"+"bbb",并且把结果值赋给一个临时变量,再执行临时变量和"ccc"相加,最后把相加的结果再赋值给abc。But,其实C#编译器比想象中要聪明得多,以下的C#代码和IL代码可以充分说明C#编译器的智能:

   // The first format
    string first = "aaa" + "bbb" + "ccc";
    // The second format
    string second = "aaabbbccc";
    // Display string 
    Console.WriteLine(first);
    Console.WriteLine(second);

该C#代码的IL代码如下图所示:

正如我们所看到的,string abc="aaa"+"bbb"+"ccc";这样的表达式被C#编译器看成一个完整的字符串"aaabbbccc",而不是执行某些拼接方法,可以将其看作是C#编译器的优化,所以在本次内存分配中只是在栈中分配了一个存储字符串引用的内存块,以及在托管堆分配了一块存储"aaabbbccc"字符串对象的内存块。

那么,我们的常规思路在.NET程序中又是怎么体现的呢?我们来看一下一段代码:

   int num = 1;
    string str = "aaa" + num.ToString();
    Console.WriteLine(str);

这里我们首先初始化了一个int类型的变量,其次初始化了一个string类型的字符串,并执行 + 操作,这时我们来看看其对应的IL代码:

    int num = 1;
    string str = "aaa" + num.ToString();
    Console.WriteLine(str);

这里我们首先初始化了一个int类型的变量,其次初始化了一个string类型的字符串,并执行 + 操作,这时我们来看看其对应的IL代码:

如上图所示,在这段代码中执行 + 操作,会调用String的Concat方法,该方法需要传入两个string类型的参数,也就产生了另一个string类型的临时变量。换句话说,在此次内存分配中,堆栈中会分配一个存储字符串引用的内存块,在托管堆则分配了两块内存块,分别存储了存储"aaa"字符串对象和"1"字符串对象。

可能这段代码还是不熟悉,我们再来看看下面一段代码,我们就感觉十分亲切熟悉了:

 string str = "aaa";
    str += "bbb";
    str += "ccc";
    Console.WriteLine(str);

其对应的IL代码如下图所示:

如图可以看出,在拼接过程中产生了两个临时字符串对象,并调用了两次String.Concat方法进行拼接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值