一、内存问题
在前面的文章中反复分析过内存的相关异常,也提到过资源耗尽(Exhaustion)和栈溢出(Overflow)。不管是前者还是后者,遇到这种情况,对于C++程序来说,基本就只有Crash的结果了。针对这两种情况,本文将对二者进行对比分析。
二、栈溢出
顺道提一嘴,一般来说,堆是堆,栈是栈,但如果直接提“堆栈”,习惯是指栈,但还是要根据上下文进行具体分析。栈溢出,通常是指栈的空间不足,即地方不够大了。栈是由系统来控制管理的,栈的大小都是有限制的。这种限制,在大小上来讲,是非常严格的。正常情况下,都会限制在M级。相对于现在的内存大小,这已经是很小的了。所以,这种小内存在应用中就会非常容易陷入空间不足的境界。常见的导致栈溢出的原因有:
- 无控制的过深的递归
- 较大的局部变量如数组或对象等
- 函数调用堆栈过深(这个和递归调用类似)
常见的栈溢出的实际场景,多见于线程内的递归调用和较大的局部数组。直接的函数调用过深,这种还是比较少见的。
三、资源耗尽
而资源耗尽就是一个更为常见的现象,特别是其中的内存耗尽。如果大家有早期的UI开发的经验,特别是MFC之类的开发经验,早期会常见一些资源耗尽导致的程序问题,比如画笔、HDC等等。其实不光界面会有这种情况,诸如文件句柄、锁、IO等等。
导致资源耗尽的的原因主要有:
- 超限制的分配,如不受控的循环、递归等导致的资源分配耗尽
- 资源泄露,特别是在长时间运行的程序中,不断的释放但未回收,极易导致资源耗尽
- 资源的不匹配,比如内存碎片过多,虽然有内存,但无法分配大于碎片大小的内存
四、应对的方法
对于上述问题的应对之法,其实在C++中还是有相对成熟的方法,
对栈溢出常用的方法有:
- 严格限定递归或循环的终止条件
- 严格控制栈上变量分配的大小
- 严格进行代码走查并借用相关工具进行分析
对资源耗尽常用的方法有: - 使用智能指针来处理大多数的内存泄露的问题,当然也要防备其中的一些特殊情况,如循环引用的问题
- 使用RAII,自动处理资源的控制
- 使用资源池,并设置限定阀值,防止出现意外情况,如内存池、线程池等
- 在编码级别进行代码走查并借助相关工具进行分析,如内存常见的cppcheck等
五、总结
基础的问题是一种沉默的问题,它可能不会怎么影响大多数的代码开发,但真到了见直章时,关键的细节把控往往是解决问题的“封喉”一剑。所以,对技术的学习和提高需要开发者把基础打牢,特别是大梁一定要坚固无比。这才是可以构建更高楼层的方法。

670





