对C/C++程序员来说,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构成的模块跑起来后才出现内存崩溃,是很让人痛苦的。因为崩溃的位置在时间和空间上,通常是在距真正的错误源一段距离之后才表现出来。前几天线上模块因堆内存写越界1个字节引起各种诡异崩溃,定位问题过程中的折腾仍历历在目,今天读到《深入理解计算机系统》第9章-虚拟存储器,发现书中总结了C程序中常见的内存操作有关的10种典型编程错误,总结的比较全面。故作为笔记,记录于此。

http://blog.csdn.net/slvher/article/details/9150597

1. 间接引用无效指针
        进程虚拟地址空间的某些地址范围可能没有映射到任何有意义的数据,如果我们试图间接引用一个指向这些地址的指针,则操作系统会以Segment Fault终止进程。而且,虚拟存储器的某些区域是只读的(如.text或.rodata),试图写这些区域会以保护异常中止当前进程。
        如从stdin读取一个int变量时,scanf("%d", &val)是正确用法,若误写为scanf("%d", val)时,val的值会被解释为一个地址,并试图向该地址写数据。在最好的情况下,进程立即异常中止。在最坏的情况下,val的值恰好对应于虚拟存储器的某个合法的具有读/写权限的内存区域,于是该内存单元会被改写,而这通常会在相当长的一段时间后造成灾难性的、令人困惑的后果。

2. 读未初始化的存储器
        C语言的malloc并不负责初始化申请到的内存区域,因此,常见的错误是假设堆存储器被初始化为0,例如:

3. 栈缓冲区溢出
         例如:

    上面的代码导致栈缓冲区溢出,安全的做法是:1)根据需求定义合适的buffer;2)采用snprintf(buf, sizeof(buf), "%s", "hello world")来及时截断。

4. 误认为指针与其指向的对象是相同大小的
        例如:

5. 造成错位错误
         错位(Off-by-one)错误是另一种常见的覆盖错误来源:

6. 引用指针,而不是它所指向的对象
        如果不注意C操作符的优先级和结合性,就会错误地操作指针,而不是指针所指向的对象。
        比如下面的函数,其目的是删除一个有*size项的二叉堆里的第一项,然后对剩下的*size-1项重建堆:

上述代码中,由于--和*优先级相同,从右向左结合,所以*size--其实减少的是指针自己的值,而非其指向的整数的值。因此,谨记:当你对优先级和结合性有疑问时,就应该使用括号。

7. 误解指针运算
        在C/C++中,指针的算术操作是以它们指向的对象的大小为单位来进行的。例如下面函数的功能是扫描一个int的数组,并返回一个指针,指向val的首次出现:

8. 引用不存在的变量
           C/C++新手不理解栈的规则时,可能会引用不再合法的本地变量,例如:

函数返回的指针(假设为p)指向栈中的局部变量,但该变量在函数返回后随着stackref栈帧的销毁已经不再有效。也即:尽管函数返回的指针p仍然指向一个合法的存储器地址,但它已经不再指向一个合法的变量了。当程序后续调用其它函数时,存储器将重用刚才销毁栈帧处的存储器区域。再后来,如果程序分配某个值给*p,那么它可能实际上正在修改另一个函数栈帧中的数据,从而潜在地带来灾难性的、令人困惑的后果。

9. 引用空闲堆块中的数据
        典型的错误为:引用已经被释放了的堆块中的数据,例如:

10. 内存泄露
       内存泄露是缓慢、隐性的杀手,当程序员忘记释放已分配块时会发生这种问题,例如:

如果leak在程序整个生命周期内只调用数次,则问题还不是很严重(但还是会浪费存储器空间),因为随着进程结束,操作系统会回收这些内存空间。但如果leak()被经常调用,那就会发生严重的内存泄露,最坏的情况下,会占用整个虚拟地址空间。对于像守护进程和服务器这样的程序来说,内存泄露是严重的bug,必须加以重视。

【参考资料】
《深入理解计算机系统》第9章 — 虚拟存储器

============== EOF ==================

《深入理解计算机系统》C程序中常见的内存操作有关的典型编程错误的更多相关文章

  1. 【转】《深入理解计算机系统》C程序中常见的内存操作有关的典型编程错误

    原文地址:http://blog.csdn.net/slvher/article/details/9150597 对C/C++程序员来说,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构 ...

  2. 错误内存【读书笔记】C程序中常见的内存操作有关的典型编程错误

    题记:写这篇博客要主是加深自己对错误内存的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢. 对C/C++程序员来讲,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构成的 ...

  3. C程序中常见的内存操作错误

    对C/C++程序员来说,管理和使用虚拟存储器可能是个困难的, 容易出错的任务.与存储器有关的错误属于那些令人惊恐的错误, 因为它们在时间和空间上, 经常是在距错误源一段距离之后才表现出来. 将错误的数 ...

  4. 对开发中常见的内存泄露,GDI泄露进行检测

    对开发中常见的内存泄露,GDI泄露进行检测 一.GDI泄露检测方法: 在软件测试阶段,可以通过procexp.exe 工具,或是通过任务管理器中选择GDI对象来查看软件GDI的对象是使用情况. 注意点 ...

  5. Android中常见的内存泄漏

    为什么会产生内存泄漏? 当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏. ...

  6. JavaScript中常见的数组操作函数及用法

    JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...

  7. JavaScript中常见的字符串操作函数及用法

    JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...

  8. JavaScript 中常见的内存泄露陷阱(摘)

    内存泄露是每个开发者最终都不得不面对的问题.即便使用自动内存管理的语言,你还是会碰到一些内存泄漏的情况.内存泄露会导致一系列问题,比如:运行缓慢,崩溃,高延迟,甚至一些与其他应用相关的问题. 什么是内 ...

  9. 谈谈.NET中常见的内存泄露问题——GC、委托事件和弱引用

    其实吧,内存泄露一直是个令人头疼的问题,在带有GC的语言中这个情况得到了很大的好转,但是仍然可能会有问题.一.什么是内存泄露(memory leak)?内存泄露不是指内存坏了,也不是指内存没插稳漏出来 ...

随机推荐

  1. linux系统下搭建自己的web服务器

    之前在windows 2008 server上搭建了一个用于测试的web服务器,但是在打开网站的时候特别的慢,尤其是图片的加载都会失败,当时以为是路径的问题,但是在服务器上自己打开都特别慢,自己实在找 ...

  2. PV信号量的一些理解

    进程通常分为就绪.运行和阻塞三个工作状态.三种状态在某些条件下可以转换,三者之间的转换关系如下:   进程三个状态之间的转换就是靠PV操作来控制的.PV操作主要就是P操作.V操作和信号量.其中信号量起 ...

  3. Vim 的补全模式加速器,轻松玩转全部 15 种自动补全模式

    1. 关于 Vim 补全模式    ---- Vim 一共提供了 15 种自动补全的模式(:help ins-completion).其中有两种的补全列表内容与另外两种相同,只是排序不同,这 15 种 ...

  4. fiddlercore 抓包获取cookie的方法

    public partial class form1 : Form { public form1() { string cookies = ""; InitializeCompon ...

  5. js动态生成按钮,页面用DIV简单布局2

    对前边不完善的修改 <!DOCTYPE html><html><head><title>test.html</title> <meta ...

  6. PHP中长连接的实现

    最近遇到PHP程序在执行大量数据的时候提示超时,于是用到了set_time_limit()函数来设置PHP页面的最大运行时间. 设置允许脚本运行的秒数.如果这是默认的,该脚本返回一个致命的错误.默认限 ...

  7. 转:C# 泛型编程之泛型类、泛型方法、泛型约束

    C# 泛型编程之泛型类.泛型方法.泛型约束 分类: asp.net c#2012-08-07 17:36 5998人阅读 评论(0) 收藏 举报 c#编程classobject编译器struct 泛型 ...

  8. ZOJ 2624 Popo's Lamps(DP 记忆化搜索)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2624 题目大意:popo要将给定数量的灯变成自己想要的颜色,有一 ...

  9. mysql与Navicat for MySQL的衔接配置问题【原创】

    首先改一下php的配置文件: 这里主要该两个地方:Cirl + F 查找到mysql.dll 然后去掉前面的";" 然后是修改路径:Cirl + F 查找到extension_di ...

  10. 队列(链式存储)C++模板实现

    #include <iostream> using namespace std; //队列结点类 template <typename T> class QueueNode{ ...