动态链接库中分配内存引起的问题-- windows已在XX.exe中触发一个断点

简介: 动态链接库中分配内存引起的        本文主要是探讨关于在动态链接库分配的内存在主程序中释放所产生的问题,该问题是我在刚做的PJP工程中所遇到的,由于刚碰到之时感动比较诡异(这也是学识不够所致),所以将它写下来,大家一起分享.

动态链接库中分配内存引起的

       本文主要是探讨关于在动态链接库分配的内存在主程序中释放所产生的问题,该问题是我在刚做的PJP工程中所遇到的,由于刚碰到之时感动比较诡异(这也是学识不够所致),所以将它写下来,大家一起分享.

       问题来由:

由于该工程中要用到声音,所以我的分工之一就是用DirectMusic和DirectSound来开发声音播放的动态库,以提供给该工程的两个部分:仿真控制部分( 语音 )和三维部分( 场景声音 )使用,两个工程中的声音都以单独的线程播放,且两个线程几乎相同.,然而该动态库在以前的运行中一直没有出现过问题, 直到工程开发即将要结束阶段的前一个星期,我碰才到了这个问题,首先是三维部分中声音在第一次播放是没有问题,在播放第二个声音就出了问题(老是这样),但是仿真控制部分还是没有出现问题,我查不出错误,就用前一天的三维的版本来运行,重新生成后声音播放没有问题,初步以为是我同事当天写的代码有问题,可是第二天,同样的问题又发生了,还是那样,三维有问题,仿真部分没问题,怎么回事呢?我将三维的声音线程写成和仿真部分一样的,还是三维出问题,仿真没问题.我不相信是动态库中出问题,同一个动态库,同样的代码,只是在两个不同的程序里,为什么一个出问题,而另一个不出问题呢?

       出错信息如下:

                  windows已在PowipD.exe中触发一个断点.
                  其原因可能是堆被损坏,这也说明PowipD.exe中或它所加载的任何DLL中有bug.
                  输出窗口可能提供了更多诊断信息

       按下中断后输入窗口出现的信息如下:

               HEAP[PowipD.exe]:Invalid Address specified to RtlValidateHeap( 01CC0000, 03723758 )
               Windows已在PowipD.exe中触发一个断点.
               输出窗口可能提供了更多诊断信息

       由于这些原因让我迷惑不解,到底是为什么出现这种奇怪的事情呢?问题出在那里?

 

问题的解决:

简单地说:DLL中分配的内存DLL要负责释放!(一个模块分配的内存要在同一个模块中释放!)

找到解决方法后我查看了三个工程的设置(三个工程皆用VS2005开发):

       三维:使用MDd(多线程调试DLL)运行期库

       仿真控制:使用MTd(多线程调试)运行期库

       声音动态库:使用MDd(多线程调试DLL)运行期库

于是,我将三个工程皆改为:使用MDd(多线程调试DLL)运行期库时,问题解决。

但是如果三个工程中有的不是用C/C++写的,或者其中有工程的设置已经不便更改了,那又有什么办法呢?

该问题主要是关于DLL与进程的地址空间的问题(下面是<<核心编程>>中的一段话):

单个地址空间是由一个可执行模块和若干个DLL模块组成,这些模块中,有些可以链接到静态版本的C/C++运行期库, 有些可以链接到一个DLL版本的运行期库,而有些模块(如果不是用C/C++编写的话)则根本不需要C/C++运行期库,许多开发人员经常会犯一个常见的错误,因为他们忘记了若干个C/C++运行期库可以存在于单个地址空间中.请看下面的代码(下面代码不是书上的):

DLL中如下:

       int *DllFunc()

{

       int *p = new int;

       return p;

}

 

EXE中如下:

void EXEFunc()

{

       int *p = DllFunc();

       if( p!= NULL )

              delete p;

}

 

如何看待这个问题呢?上面的代码能够正确运行吗?DLL函数分配的内存是由EXE的函数释放的吗?答案是可能的.上面显示的代码并没有提供足够的信息.如果EXE和DLL都链接到DLL的C/C++运行期库,那么上面的代码将能够很好地运行.但是,如果两个模块中的一个或者两个链接到静态C/C++运行期库,那个对delete的操作就会失败.

一个很方便的方法可以解决这个问题.当一个模块提供一个用于分配内存块的函数时,该模块也必须提供相应的释放内存的函数,将上面的代码改成如下的样子就不会出错了:

 

DLL中如下:

       int *DllFunc()

{

       int *p = new int;

       return p;

}

 

void DLLDelete( int *p)

{

       if( p != NULL )

              delete p;

}

 

EXE中如下:

void EXEFunc()

{

       int *p = DllFunc();

       DLLDelete( p );

}

这样的代码才是正确的,当我将代码改成如上类似后,再将三维的运行期库改为原来一样(使用MDd(多线程调试DLL)运行期库),三维的声音也正确无误地播放出来了。当你在编写一个模块时,你时刻都得记着,别人的代码不一定是用C/C++写的,也有可能不能同时链接到DLL的C/C++运行期库。malloc和free函数也有类似的问题。

当然在你在生成你的模块时是可以选择运行期库的,VC 6.0配有6个运行期库:其描述如下:

 

库名

描述

LibC.lib

用于单线程应用程序的静态应用程序的静态链接库      

LibCD.lib

用于单线程应用程序的静态链接库的调试版

LibCMt.lib

用于多线程应用程序的静态链接库的发行版

LibCMtD.lib

用于多线程应用程序的静态链接库的调试版

MSVCRt.lib

用于动态链接MSVCRt.dll库的发行版的输入库

MSVCRtD.lib

用于动态链接MSVCRtD.dll的调试版的输入库。该库同时支持单线程应用程序和多线程应用程序

 

而VS2005中只配了4个C/C++运行期库,就是上表中的后面4个。

建议各位在软件开发时同一软件的不同模块最好使用一致的运行库,否则还可能出现链接问题。

目录
相关文章
|
7月前
|
存储 程序员 编译器
在C语言中.如何正确地分配和释放内存docx
在C语言中.如何正确地分配和释放内存docx
52 1
|
10天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
55 12
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
70 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
2月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
57 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
4月前
|
关系型数据库 MySQL
MySQl优化:使用 jemalloc 分配内存
MySQl优化:使用 jemalloc 分配内存
|
4月前
|
缓存 Java 编译器
Go 中的内存布局和分配原理
Go 中的内存布局和分配原理
|
5月前
|
存储 缓存 算法
(五)JVM成神路之对象内存布局、分配过程、从生至死历程、强弱软虚引用全面剖析
在上篇文章中曾详细谈到了JVM的内存区域,其中也曾提及了:Java程序运行过程中,绝大部分创建的对象都会被分配在堆空间内。而本篇文章则会站在对象实例的角度,阐述一个Java对象从生到死的历程、Java对象在内存中的布局以及对象引用类型。
131 8
|
5月前
|
Java Linux 容器
JVM内存问题之什么是OOM-Killer,它通常会在什么情况下触发
JVM内存问题之什么是OOM-Killer,它通常会在什么情况下触发
118 2
|
5月前
|
NoSQL Redis C++
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
|
5月前
|
Java 运维
开发与运维内存问题之在堆内存中新创建的对象通常首先分配如何解决
开发与运维内存问题之在堆内存中新创建的对象通常首先分配如何解决
24 1