对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. C语言细节总结笔记

    C语言细节总结笔记 */--> C语言细节总结笔记 Table of Contents 1. 三步异或法交换数字 2. 做差法交换数字 3. 按n位置位 4. 求余求商求积 5. 辗除法求最大公 ...

  2. BeanFactory与FactoryBean

    1. BeanFactory BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是Spring IOC 所遵守的最底层和最基本的编程规范.在  ...

  3. wamp 提示 Directive allow_call_time_pass_reference is no longer avaiable in PHP

    在wamp运行时,提示"Directive allow_call_time_pass_reference is no longer avaiable in PHP",点击确定之后, ...

  4. angularjs的一些优化小技巧

    尽可能少调用 ng-repeat ng-repeat默认会创建很多监听器,所以在数据量很大的时候,这个非常消耗页面性能,我觉的只有在当需要经常更新数据列表的时候才需要用ng-repeat,要不然放那么 ...

  5. oracle的sid

    SID是一个数据库的唯一标识符!是你在建立一个数据库时系统自动赋予的一个初始ID,虽说他和数据库名(DB_NAME)都是一个数据库的唯一标识符,但是在作用上就有不小区别.SID主要用于在一些DBA操作 ...

  6. 将系统日期转化为sharepoint日期

    string currentDate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now.Date);

  7. SQL Server调优系列进阶篇 - 深入剖析统计信息

    前言 经过前几篇的分析,其实大体已经初窥到SQL Server统计信息的重要性了,所以本篇就要祭出这个神器了. 该篇内容会很长,坐好板凳,瓜子零食之类... 不废话,进正题 技术准备 数据库版本为SQ ...

  8. Could not find artifact com.sun:tools:jar:1.5.0解决方法

    可以参照在XP系统下搭建maven环境出的问题 Unable to locate the Javac Compiler in: C:\Program Files\Java\jre6\..\lib\to ...

  9. 第七篇、hitTest UITabbar中间突出按钮额外增加可点击区域

    简介: 以前UITabbar使用中间有一个凸起按钮时,常常就需要用到hitTest来处理可点击的范围. 示例代码: - (UIView *)hitTest:(CGPoint)point withEve ...

  10. C#中常用修饰符

    1.存取修饰符 public:(公有的)存取不受限制 protected:(受保护的)只有包含该成员的类以及派生类可以存取  private:(私有的)只有包含该成员的类可以使用 2.类修饰符 abs ...