一、内存问题引发的现象
在实际使用电脑过程中,经常会遇到电脑卡住了,鼠标和键盘也没反应。这时候儿会怎么办?其实此时打开任务管理器,就可以发现,有几种情况:一是CPU占用过高;二是IO占用过高;最后就是内存占用过高。当然,实际场景可能会是上面几种情况混合出现。本文就着重分析一下内存的问题。
在前面反复讨论过内存泄露的问题,并针对内存泄露进行了各种方面的分析,包括工具使用、插桩处理等。但其实内存引起的问题远不止这么一些,说句夸张的话,基本上程序开发大多数的问题都与内存有关。可以这样说,内存问题始终是编程绕不过去的山。即使如JAVA等这种自带内存管理的语言,经常也会出现OOM的问题,所以内存问题在编程中的重要性不言面喻。
这里举一个亲身经历的例子。在原来的一个项目中,开发了一个服务端安装到一台DELL的服务器上。测试时一切正常,运行也非常稳定。但工程部门安装到现场后,运行一个多月,客户就反馈说服务端访问经常中断,需要不断的重连甚至连接不上。于是在本地模拟了一下反馈的情况和猜测相关的原因,都找不到结果。只好去了现场,结果一打开服务器,发现内存已经达到了百分百的占用,日志显示在分配接收的几百字节的缓冲区时都经常会分配失败。就给工程部门建议换了条大内存就解决了问题。当时感觉是,服务器就是好啊,内存都百分百的占用了还能稳定运行,且大概率情况下都能和客户端正常通信。
二、主要原因
内存的问题表象有千千万,但其实总结起来主要有以下几部分:
1、内存泄露
这是罪魁祸首,不过一定要明白,真正难缠的不是简单的内存泄露而是内存泄露的累积。对如今庞大的内存来说,泄露个几M甚至几G都不是多大问题。但如果程序会不断的泄露,时间长了,就把内存给搞没了。自然,程序也就完蛋了。
2、内存分配机制不合理
这个涉及的就比较多,包括长生命周期大内存的分配(内存只开辟不回收)导致整个系统的内存占用太高,造成别的程序的内存问题;还有小内存的反复分配导致的内存碎片;内存的管理问题,如double free和悬垂指针、空指针等。
3、内存溢出
这个也是一个较常见的问题,也是引起程序崩溃的一个重要原因。打个比方,就是在人际交往中过界了,然后两个人闹崩了。
4、失控的缓存和缓冲区
这个有点类似于第二种原因,大量的缓存和缓冲区占用了内存不断堆积,可能有的开发者说缓存不大啊,但关键电脑上运行了N多的程序,每个程序都会有缓存的,这都有可能导致内存的占用超出正常状态出现各种奇怪的问题。
5、内存访问导致的问题
这个一般来说在特殊情况比较常见,比如在互联网应用中的内存型数据库或者自己要管理大内存的情况下,调试机制问题导致的缓存命中失败或缺页等问题引起的一系列情况。
6、内存安全保护问题
这个涉及到很多,包括黑客、木马等非常规手段,也包括如多线程访问同一块内存引起的内存异常的问题。
7、其它
这个最典型的就是内存对齐的问题,当然也有其它问题,大家关注到就可以了。
三、如何判断
1、Review代码
包括自己或交叉Review代码,从代码中发现问题
2、使用工具
使用包括内存静态检测工具和动态检测工具等的内存安全检查软件,如valgrind、cppcheck、Clang-Tidy、Coverity等,甚至包括一些常见的命令如top,vmstat,free等,当然,引入AI分析更可以
3、在代码中的处理
在开发中,使用一些较好的编程技术如智能指针和RAII等控制并减少内存问题的出现;安装各种桩,比如异常控制、分配错误控制等等在出现问题时易于发现并解决 ;处理内存对齐,加强多线程间的况态控制等;不断重构并优化内存管理的相关代码,适时的引入更先进的框架或标准。
4、加强对缓存和缓冲区的控制
对电脑中所有的应用程序的缓存或缓冲区的设置要保持敏感性,定期查看相关内存占用的大小并根据情况进行处理
四、总结
内存问题是一个非常重要的问题,即使反复讨论也是必要的。俗话说的好“有千日做贼没有千日防贼”的,内存问题就是这样。再谨慎的开发者或设计者,总有老虎打盹儿的时候。所以提高警惕掌握内存问题的实质,才能更好的从设计和开发层面避免它。哪怕万一真遇到了内存问题,也能从根本上找到问题的根源并加以解决。
知其然更要知其所以然。