1、内存分配错误
动态内存分配错误有两种基本类型:内存错误和内存泄漏。
(1)内存错误
当一个指针或者该指针所指向的内存单元成为无效单元,或者内存中分配的数据结构被破坏时,就会造成内存错误。指针未被初始化,指针被初始化为一个无效地址,指针被不小心错误地修改,在与指针相关联的内存区域被释放后使用该指针(这种指针被称为虚悬(dangling)指针),这些都会使指针变为无效指针。当通过一个错误指针或者虚悬指针对内存进行写入,或者将指针强制转换为不匹配的数据结构,又或者是写数据越界,内存自身也会遭到破坏。删除未被初始化的指针、删除非堆指针、多次删除同一指针或者覆盖一个指针的内部数据结构,都会造成内存分配系统错误。
(2)内存泄漏
内存泄漏在被动态分配的内存没有被释放时产生。有许多情况会导致内存泄漏,如没有在程序的全部执行路径中释放内存,没有在析构函数中释放所有的内存等。一个程序在崩溃之前可运行的时间越长,则导致崩溃的原因与内存泄漏的关系越大。
Windows会在程序结束的时候将泄漏的内存收回,因此内存泄漏是个暂时性的问题。但为什么必须消除内存泄露呢?首先,内存泄漏往往会导致系统资源的泄漏。动态分配内存往往不仅仅代表一块存储区域,还代表了某些类型的系统资源,如文件、窗口、设备上下文、GDI对象等。其次,高质量的程序和特定的服务器程序必须能够无限地运行下去。最后,内存泄漏往往是其他程序错误或不良编程习惯的征兆。
导致内参泄漏的原因:忘记释放内存;构造函数失败;存在内存泄漏的析构函数;存在内存泄漏的异常处理程序;多个返回语句;使用错误形式的delete。
2、关于内存的初始化
在调试版本里,堆里未被初始化的内存被0xCD字节模式填充,堆里释放的内存被0xDD字节模式填充。堆栈里被初始化的内存被0xCC字节模式填充。调试版本和发布版本里,未被初始化的全局内存都被初始化为0。
3、内存虚拟地址空间
Windows使用一组固定的范围来分割进程的4GB虚拟地址空间,因此有时可通过查看指针的返回值来判断指针是否有效。
(1)Windows2000虚拟地址空间划分
0~0XFFFF(64KB):不能用来检测空指针赋值(访问冲突)
0x10000(64KB)~0x7FFEFFFF(2GB-64KB):Win32进程私有的(非保留的),用于程序代码和数据
0x7FFF0000(2GB-64KB)~0x7FFFFFFF(2GB):不能用来防止覆盖OS分区(访问冲突)
0x800000000(2GB)~0xFFFFFFFF(4GB):为操作系统保留,不可访问(访问冲突)
(2)Windows2000虚拟地址空间使用
0x00030000~0x0012FFFF:线程栈
0x00130000~0x003FFFFF:堆(有时堆位于此处)
0x00400000~0x005FFFFF:可执行代码
0x00600000~0x0FFFFFFF:堆(有时堆位于此处)
0x10000000~0x5FFFFFFF:App DLLs、Msvcrt.dll、Mfc42.dll
0x77000000~0xFFFFFFFF:Advapi32.dll、Comctl32.dll、Gdi32.dll、Kernel32.dll、Ntdll.dll、Rpcrt4.dll、Shell32.dll、User32.dll
其中,0x00400000是所有版本的Windows能使用的最低基地址。
动态内存分配错误有两种基本类型:内存错误和内存泄漏。
(1)内存错误
当一个指针或者该指针所指向的内存单元成为无效单元,或者内存中分配的数据结构被破坏时,就会造成内存错误。指针未被初始化,指针被初始化为一个无效地址,指针被不小心错误地修改,在与指针相关联的内存区域被释放后使用该指针(这种指针被称为虚悬(dangling)指针),这些都会使指针变为无效指针。当通过一个错误指针或者虚悬指针对内存进行写入,或者将指针强制转换为不匹配的数据结构,又或者是写数据越界,内存自身也会遭到破坏。删除未被初始化的指针、删除非堆指针、多次删除同一指针或者覆盖一个指针的内部数据结构,都会造成内存分配系统错误。
(2)内存泄漏
内存泄漏在被动态分配的内存没有被释放时产生。有许多情况会导致内存泄漏,如没有在程序的全部执行路径中释放内存,没有在析构函数中释放所有的内存等。一个程序在崩溃之前可运行的时间越长,则导致崩溃的原因与内存泄漏的关系越大。
Windows会在程序结束的时候将泄漏的内存收回,因此内存泄漏是个暂时性的问题。但为什么必须消除内存泄露呢?首先,内存泄漏往往会导致系统资源的泄漏。动态分配内存往往不仅仅代表一块存储区域,还代表了某些类型的系统资源,如文件、窗口、设备上下文、GDI对象等。其次,高质量的程序和特定的服务器程序必须能够无限地运行下去。最后,内存泄漏往往是其他程序错误或不良编程习惯的征兆。
导致内参泄漏的原因:忘记释放内存;构造函数失败;存在内存泄漏的析构函数;存在内存泄漏的异常处理程序;多个返回语句;使用错误形式的delete。
2、关于内存的初始化
在调试版本里,堆里未被初始化的内存被0xCD字节模式填充,堆里释放的内存被0xDD字节模式填充。堆栈里被初始化的内存被0xCC字节模式填充。调试版本和发布版本里,未被初始化的全局内存都被初始化为0。
3、内存虚拟地址空间
Windows使用一组固定的范围来分割进程的4GB虚拟地址空间,因此有时可通过查看指针的返回值来判断指针是否有效。
(1)Windows2000虚拟地址空间划分
0~0XFFFF(64KB):不能用来检测空指针赋值(访问冲突)
0x10000(64KB)~0x7FFEFFFF(2GB-64KB):Win32进程私有的(非保留的),用于程序代码和数据
0x7FFF0000(2GB-64KB)~0x7FFFFFFF(2GB):不能用来防止覆盖OS分区(访问冲突)
0x800000000(2GB)~0xFFFFFFFF(4GB):为操作系统保留,不可访问(访问冲突)
(2)Windows2000虚拟地址空间使用
0x00030000~0x0012FFFF:线程栈
0x00130000~0x003FFFFF:堆(有时堆位于此处)
0x00400000~0x005FFFFF:可执行代码
0x00600000~0x0FFFFFFF:堆(有时堆位于此处)
0x10000000~0x5FFFFFFF:App DLLs、Msvcrt.dll、Mfc42.dll
0x77000000~0xFFFFFFFF:Advapi32.dll、Comctl32.dll、Gdi32.dll、Kernel32.dll、Ntdll.dll、Rpcrt4.dll、Shell32.dll、User32.dll
其中,0x00400000是所有版本的Windows能使用的最低基地址。