有这样一道阿里笔试题:
C++内存分配中说法错误的是( )。
A.对于栈来说,生长方向是向上的,也就是向着内存地址增加的方向
B.对于堆,大量的new/delete操作会造成内存空间不连续
C.堆容易产生memory leak
D.堆的效率比栈要低很多
E.栈变量引用容易逃逸
F.以上都对
【答 案】A、F
【解 析】C++将各类变量分配在不同的区域中,主要有栈、堆、自由存储区、全局/静态存储区及常量存储区等。
题目中提到的几种存储空间的特性如下。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。栈中的变量通常是局部变量、函数参数等。在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。用户栈在程序执行期间可以动态地扩展和收缩。因为栈具有先进后出的特点,故它的生长方向是向下的,是向着内存地址减小的方向增长。选项A是错误的。
堆,就是那些由new分配的内存块,这种内存的释放不由编译器管理,而由应用程序去控制。一般来说,一个new就要对应一个delete。如果程序员没有释放掉,会导致一直占据该内存单元,即所谓内存泄漏(选项C是正确的)。这些内存在程序结束后,操作系统才会自动回收。
对于堆来讲,频繁的new/delete操作势必会造成内存空间的不连续(选项B是正确的),从而造成大量的碎片,这会使程序效率降低(选项D是正确的)。对于栈来讲,则不会存在这个问题,因为栈是先进后出的,不可能有一个内存块从栈中间弹出,所以不会有碎片产生。
在计算机语言编译器语言优化管理中,当变量(或者对象)在方法中分配后,其指针有可能被返回或者被全局引用,这样就会被其他过程或者线程所引用,这种现象称作指针(或者引用)的逃逸(Escape)。分析指针动态范围的方法称之为逃逸分析。当一个对象的指针被多个方法或线程引用时,这个指针就发生了逃逸。例如在一个方法b内部生成的一个对象V的引用,返回给另一个方法a内的变量v时,或方法c内生成的一个对象W被赋给了全局变量global_v,就发生了指针(引用)逃逸。故选项E是正确的。
本文已收录于《横扫Offer--程序员招聘真题详解700题》一书,开点工作室著,清华大学出版社。更多程序员笔试面试真题的精彩详解请参见该书。
为保证书稿质量,作者及出版社在编写完成后经过反复多次的审核、校对和修改,力求为读者奉献一本内容详实、严谨、准确、精美的实用宝典,因此上市时间有所延后,望各位读者谅解。该书目前已进入印刷环节,预计8月下旬各大网上书店开始发售。我们将会在第一时间通知该书的上市购买信息,并将举行评论送书活动,以感谢各位读者的支持。详细情况请持续关注微信公众账号“开点工作室”。