造成内存错误的样例分析
例一:(释放代码段空间导致内存错误)
图1 Coding
运行错误显示:
图2内存错误显示
分析:如图2所示运行后出现内存错误,free(): invalid pointer: 0x08048540 ***。打印出指针P的地址可以看出如图3,P的地址发生了变化,通过malloc分配的指针P地址在堆区,但是经过字符串给P再赋值后,P的地址变成了代码段存放的地址
图3指针P的地址
图4进程运行内存显示
释放了一个代码段的内存就导致了内存的错误,并非堆内存。
样例二(释放没有申请空间的指针导致内存错误)
图5 Coding
内存错误显示
图6内存错误显示
分析:如图6所示,运行后内存错误显示。如图7所示声明并定义一个char *p,并未为其分配空间,打印P的地址可以看出位于第一个动态链接库加载的地址处。改指针并未申请空间。
图7指针P地址
图8进程运行内存显示
样例三 (释放已经释放的指针)
图9 Coding
图10运行错误显示
分析:错误提示double free corruption (fasttop):0x09303008,即释放了一个已经释放了的内存空间。
样例四(释放了栈空间变量)
图11 Coding
图12内存错误
分析:声明了一个int指针,并将变量a的地址赋予P,然后释放P的空间。由上图分析可得,P的地址为0xbfe6ec5c,通过显示的Memory map可以看出,p指向的是栈空间。由于free了栈空间,导致了内存错误。
内存泄露原因
内存泄露通常分为四类:(根据发生的方式)
1.常发性内存泄露。造成内存泄露的代码会被多次执行,每次代码被执行时都会导致一块内存泄露。
2.偶发性内存泄露。造成内存泄露的代码只有在某种特定环境或操作下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性也许就变成了常发性。所以测试环境和测试方法对检测内存泄露至关重要。
3.一次性内存泄露。造成内存泄露的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且只有一块内存发生泄露
4.隐式内存泄露。程序在运行过程中不断地分配内存,但是直到结束时候才释放内存。确切地说这里并没有发生内存泄露,因为程序最终释放了所有申请的内存。但是对于一个服务器程序来说需要需要长时间连续不间断运行,有时几个月甚至几年。如果不及时释放内存可能会导致最终耗尽系统的所有内存。
堆内存优化
1.堆内存最小单位为16字节所以应尽量减少小块内存的申请,避免内存浪费
2.调整M_MMAP_THRESHOLD,降低mmap的门槛,会降低内存空洞的风险,但也会增加系统调用,降低性能。
3.调整M_TRIM_THRESHOLD,减少堆顶连续内存门槛,释放更多的堆顶内存。