`

VC异常:Free Heap block xxxxxxxx modified at xxxxxxxx after it was freed(转)

 
阅读更多
Free Heap block xxxxxxxx modified at xxxxxxxx after it was freed

api任务socketwindowsdelete测试
方法一:如果你是C++程序员,如果你写过一个很复杂的程序,如果你经常碰到莫名其妙的崩溃问题。那么你就有可能遭遇了野指针。如果你比较细心,注意了Debug output输出窗口的话,那么你就有可能注意到这样一行提示:
HEAP:   Free   Heap   block   xxxxxxxx modified   at   xxxxxxxx after   it   was   freed
网络上关于这个问题提问的人不少,但是真正给的出答案的却少之又少。在网上搜索了几天,终于发现了这个问题的解决之道。下面我来介绍一下。

GFlags是windows debug tools 工具包下的一个工具,在Windows 2000的Resource Kit中也可以找得到。用来设置一些调试属性,总体上分为3个级别System, Kernel, 和 Image File。
我们设置好Path环境变量,将其指向Debug tools工具的目录下。
输入如下命令行:
gflags /p App.exe /full
或者 pageheap app.exe /full
该命令行会在注册表里设置一些调试参数,使内存在使用的时候加入了保护机制,所以一旦内存写越界,或者发生野指针的问题,都会导致一个中断。由此,你就可以确定问题到底出在哪里了。
方法二:
多线程与内存(heap)
关于多线程中的内存问题,必需足够地重视,否则,程序总是会出现莫名其妙的错误。如果幻想某些情况“应该”不会出现,或者是认为某些步骤是按照正常的顺序下来的,那就错误大大地,因为有一个简单的事实,就是你没有遵守事实,想和CPU对着干!
xx SDK的报错退出问题,从去年直到现在都没有得到有效的解决,近段时间,被频繁地爆露出来,是到了不得不直面的时候了,所以,前两周,去了xx N次,直到现在,还不能确定问题是否真地解决了
SDK的现象:
在自己的测试demo上没有问题,而在平台上就有问题
后来的测试证明,不是demo没有问题,而是原来的demo只是在跑自己测试的设备,其数量少,环境不真实,实际的情况无法得到有效的测试,所以,demo不会有任何问题
直接运行程序,就是出现调试的那种错误,在平台的vc debug模式下,出现的是触发了用户断点的错误。在SDK的vc debug模式下,爆露了错误的本质:
HEAP[pingtai.exe]: HEAP: Free Heap block 2be3000 modified at 2be3200 after it was freed
这种错误过去从没有遇到过,经查,表明是因为堆被破坏而产生错误。种种迹象表明,是因为某个内存被删除之后,其内容又被修改了,这样就是破坏了堆,就出现了这种错误,模拟程序如下:
void fun1()
{
char *p = new char[128];
delete[] p;
strcpy( p, "abcdefghijklmnopqrstuvwxyz" );
}
在我模拟的时候,其情况如下:
1. 如果我strcpy()的字节少于13个字节,则不会报任何错误。此情况并不绝对
2. 当fun1()返回时,并不出错,当程序退出时,报错
3. 在fun1()返回后,再调用其它任何函数,即会报错
为方便后面的叙述,把错误的描述如下:
HEAP[<exe>]: HEAP: Free Heap block <addr1> modified at <addr2> after it was freed
对模拟程序的报错进行分析,得出如下结论:
对内存<addr1>进行了删除,然后,又修改了内存<addr2>处的内容,其中,<addr2>是被包含在<addr1>中的,形式如下:
|------------------------------|
| <addr1> | <addr2>           |
|------------------------------|
在模拟程序中,<addr1> = p,<addr2> >= p 且 <addr2> < p + 128
在真实的内存中,<addr1>并不是等于p,而是会比p小,其不表示程序代码中的任何一个内存,而是在new时,用于保存p的内存而产生的内存指针,该指针由windows保存和维护(注:个人认为,通过计算,应该是可以得到p的地址),实际的模式如下:
|------------------------------|
| <addr1> | p                 |
|------------------------------|
<addr1>是windows占用的内存,而p是程序占用的内存
既然内存的操作已经明确,而且也知道了如何产生了这种错误,那么就要根据<addr2>来找是程序中哪个地方出现了这种情况,采用倒推 的方式,即首先根据<addr2>找到是哪个内存被删除后又重新进行了附值(或者是其中的某处被重新附值),然后再根据情况来使删除和附值不 要冲突
程序的顺序应该没有问题,因为都是删除后就不再进行附值操作,或者是其它任何使用的可能了,所以,从需要分配内存(主要是char*类型的内存分 配)变量开始找起。把所有new出来的char*指针地址及其长度打印出来,从上万行的打印信息中一个一个查找,却发现没有<addr2>
这就奇怪了,难道是程序的执行顺序出现了问题?不可能吧
把所有new出来的类地址及其内存范围进行打印,再一行一行地仔细找,汗......
竟然是CAccept类出现了这种情况!难道其删除之后,还有被使用的情况发生?根据以上内存的分析,肯定是有这种使用情况存在,否则....,找!
因为CAccept的类使用较少,找起来也比较容易,主要就在两个地方使用,一个是完成端口的死循环中,一个是任务检查的死循环中,肯定是这两个地方的使用有冲突。
完成端口的工作模式:
while( true )
{
if ( !getcompleteio() )
break;
if ( isaccept() )
{
CAccept *pacc = getaccept(); // 从列表中获取
// 使用pacc,其中有附值操作
... ...
// 删除pacc
SAFE_DELETE(pacc)
}
else
{
// 数据收发及socket端口的其它消息处理
}
}
任务检查的工作模式:
while ( true )
{
wait(5000); // 等待5秒钟,开始任务检查
lock();
while ( not_end_accept_list )
{
CAccept *pacc = nextaccept();
if ( pacc->tooLongTime )
SAFE_DELETE(pacc) // 删除 pacc
}
unlock();
// 连接检查
...
}
对accept的操作子函数(比如createaccept()、getaccept()、deleteaccept()等),都是被放入临界区中 的,这里仔细检查发现,完成端口中对CAccept的使用没有被放入临界区中,虽然其getaccept()中有临界区的操作,虽然任务检查中对 accept列表的操作也是在临界区中进行的,那么,问题肯定就是出现在了这里。为了验证,对任务检查处的accept删除和在完成端口中对accept 的使用进行信息打印,发现,当完成端口中还没有对其获取的CAccept使用完时,已经被任务检查的循环删除了!
这种情况在正常情况很难出现,为 了使它容易出现,对临界区的操作加了延时,即人为使每个操作都等待较长的时间(原来是没有任何等待的),比如100毫秒,或者50毫秒等,这样,可以使很 多的操作都被挂起,在设备的连接达到一定多的时候,这种挂起的操作会越集越多,采用这种方法,可以使一些问题较容易地复现出来
找到问题了,解决起 来应该是比较容易的了(有些可是棘手的,比如完成端口中else分支里的socket消息的处理),只需要在完成端口中把对CAccept的使用也放入相 应的临界区中即可,修改完毕,测试,再也没有CAccept的堆问题了,至此,该部分的问题已“完美”地被解决了,那个痛快啊---------,就别提 了... ...
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
还有两个问题,一个是关于上层对SDK的调用问题,一个是SDK内部的问题。
这两个问题,都和以上的问题的本质一样,就是删除了后还在使用!
1. 上层对SDK的调用
SDK 已经通知了上层设备断开,但是,上层在得到该消息之后,竟然还在调用相应的接口。这本身不成问题,因为上层调用SDK的时候,SDK会从相关的设备列表中 获取相应的连接,然后拿这个连接对设备进行操作,如果是该设备已经断开,那自然就会从相应的列表中删除掉,那么在上层调用的API中获取连接时,肯定是获 取失败,SDK在判断后,自然直接返回失败。没错!你说得太对了,就是这样。...... 停!你想,仔细地想一想,然后再往下看
================================
在 SDK中,不知道上层对SDK的调用和消息接收,是在一个线程中还是两个线程中,那么,SDK无从知道上层对SDK的消息处理和API调用的先后顺序,有 一种情况,应该是比较容易理解的,当SDK向上层进行了很多的消息通知,上层可能是会把这个消息放入消息队列中,然后一个一个地慢慢处理,其处理的某一个 消息,也许是10秒钟之前的消息(有点夸张),如果是这样,而且如果刚好这个消息就是连接断开的消息,那么在其处理该消息之前的3秒钟,用户要对该设备下 发命令,用户看到的结果就是,该设备在线,即下发命令失败,而且显示的错误消息是设备不在线!这样,程序也不会出错,因为7秒了,太久了,SDK应该是已 经把这个连接从连接列表中删除了。
但不幸的是,并不总是这种情况,而是有一个糟糕的情况可能会出现。当API函数中获取到相应的连接后,正在向设 备下发命令时,连接列表被任务检查中的连接检查循环删除了(比如有1分钟都没有收到任何数据),这时,如果下发命令的函数中是读取,而不进行任何的附值操 作,则出现的错误,应该是内存非法读的异常,否则,出现的错误,应该是和上面一样的堆错误。这种错误,也许解决起来比较容易,比如在使用时,也放入临界 区,这样当然可行,只是当有100个API时,你就必需得进行100次临界区的操作,这不算重要,更重要的是,由于你在最外层增加了临界区的操作,那么在 SDK的内部,必需要小心地保证临界区的操作不会产生冲突,否则,就会发生程序无反应的情况,需要使用任务管理器来结束的后果。如果其中有附值操作,这也 许是唯一的一种解决方法,但如果是没有附值操作,则可能会比较简单,比如,我只在那时出现了这个错误的API外层,增加了 try...catch()...,这样,如果执行的中间其实例被删除了,则该API直接返回失败。具体的解决方案,可以根据实际情况的不同,进行不同的 处理,这里,只是阐明我自己的想法而已
2. SDK内部的另外一个问题
和CAccept完全一样,只是其复杂度相当大,由于其几乎涉及到程序的所有地方,所以,解决起来相当棘手,而且,由于其和要上层通讯,则一不小心,就会使临界区冲突(除了上层的代码之外,SDK中的代码都被放入临界区):
[收到socket消息] --> [通知上层] --> [上层调用SDK API] --> [API调用SDK内部的函数]
这个过程中,因为SDK通知上层后,需要等到上层返回,才进行下一步处理,上层需要调用API的返回后自己才返回,而API调用内部函数时候,可能需要先进入临界区才能操作,如此便出现了临界区的冲突。
所以,在处理收到的socket消息时,被放入临界区是比较危险的做法,所以,这里如果要找到一个好的解决方案,比较棘手
由于时间问题,暂只浅谈之
分享到:
评论

相关推荐

    java.lang.OutOfMemoryError: Java heap space 解决方法

    "Java.lang.OutOfMemoryError: Java heap space 解决方法" Java.lang.OutOfMemoryError: Java heap space 是 Java 中的一个常见错误,它发生时,Java 虚拟机 (JVM) 无法分配对象,因为堆空间不足。下面是解决该问题...

    解决报错heap corruption detected after normal block.zip

    在编程过程中,尤其是在C语言和使用Visual C++(VC)编译器的环境中,"heap corruption detected after normal block"是一个常见的错误提示,它通常表明在程序执行时内存堆出现了损坏。这个错误通常与动态内存分配(如...

    java错误处理:java.lang.OutOfMemoryError: Java heap space

    ### Java 错误处理:java.lang.OutOfMemoryError: Java heap space 在Java应用程序开发过程中,经常遇到的一个问题就是内存溢出错误,特别是在处理大量数据或长时间运行的应用时。其中,“java.lang....

    java虚拟机OutOfMemoryError:Java heap space堆dump文件

    java虚拟机OutOfMemoryError:Java heap space堆dump文件,可以直接用来分析。

    编译时出现java.lang.OutOfMemoryError Java heap space异常

    ### 编译时出现java.lang.OutOfMemoryError Java heap space异常 #### 一、问题概述 在进行Java项目编译的过程中,可能会遇到`java.lang.OutOfMemoryError: Java heap space`这种异常。这类异常通常表明Java虚拟机...

    Myeclipse下java.lang.OutOfMemoryError Java heap space的解决

    ### Myeclipse下java.lang.OutOfMemoryError: Java heap space的解决方案 在使用Myeclipse进行Java开发时,可能会遇到`java.lang.OutOfMemoryError: Java heap space`这个错误提示。这种异常通常发生在应用程序占用...

    记录java.lang.OutOfMemoryErrorJava heap space的情况.docx

    在Java程序中,`java.lang.OutOfMemoryError: Java heap space` 是一个常见的错误,意味着程序在运行过程中耗尽了JVM分配的堆内存。这个错误通常发生在创建大量对象或者单个对象占用过多内存时。 一、问题描述与...

    java解决nested exception is java.lang.OutOfMemoryError Java heap space

    Java程序在运行过程中可能会遇到各种异常,其中"nested exception is java.lang.OutOfMemoryError: Java heap space"是一个常见的问题,通常发生在程序试图分配超过堆内存限制的空间时。这个错误表明Java虚拟机(JVM...

    解决Java_heap_space问题

    ### 解决Java_heap_space问题:深入理解与策略 在Java应用程序开发与运行过程中,经常会遇到一个常见的内存管理问题——“Java heap space”。这个问题通常表现为Java虚拟机(JVM)在执行过程中因可用堆内存不足而...

    java[1].lang.OutOfMemoryError_Java_heap_space错误及处理办法

    在Java应用程序开发与维护过程中,经常会遇到`java.lang.OutOfMemoryError: Java heap space`这一异常情况。该异常通常表明Java虚拟机(JVM)的堆内存不足以支持当前程序运行所需的内存分配请求。本文将详细介绍该...

    An internal error occurred during: \"Building workspace\". Java heap space

    当程序创建过多的对象或单个对象占用过大内存,以至于超过了JVM分配的堆内存大小时,就会抛出“Java heap space”异常。 在Eclipse中,"Building workspace"是Eclipse自动构建项目的过程,它包括编译、索引更新等...

    博客代码_CrtMemTest_20111201

    本文将深入探讨一个常见的内存问题——"Free Heap block XXXX modified at XXXX after it was freed",并以"博客代码_CrtMemTest_20111201"为例进行详细解析。 首先,这个错误提示表明在C运行时库(CRT)中,程序...

    oracle:Heap size 3597K exceeds notification threshold

    ### Oracle:“Heap size 3597K exceeds notification threshold” 解决方案 #### 背景与问题描述 在Oracle数据库环境中,可能会遇到一条警告信息:“Heap size 3597K exceeds notification threshold”。这条消息...

    FibonacciHeaps.pdf

    FibonacciHeap优先队列数据结构 FibonacciHeap是一种高效的优先队列数据结构,由Michael L. Fredman和Robert Endre Tarjan在1986年提出的。它扩展了二项队列的概念,支持任意删除、插入、取最小值、降低键值等操作...

    java.lang.OutOfMemoryError 解决方法

    java.lang.OutOfMemoryError: Java heap space 解决方法

    java.lang.OutOfMemoryError处理错误

    在Tomcat中java.lang.OutOfMemoryError: Java heap space异常处理: 1. Heap size JVM堆的设置是指Java程序运行过程中JVM可以调配使用的内存空间的设置。 2. JVM在启动的时候会自动设置Heap size的值,其初始空间...

    java.lang.OutOfMemoryError解决办法

    根据提供的信息,这个错误主要涉及到两个方面:`PermGen space`和`Java heap`,并且与Tomcat服务器相关。 首先,让我们详细讨论`PermGen space`。 PermGen(Permanent Generation)是Java虚拟机(JVM)的一个内存...

    OutOfMemoryError_8种典型案例分享

    当堆内存不足以容纳新对象时,就会抛出java.lang.OutOfMemoryError: Java heap space错误。常见的解决方法是增加-Xmx参数值以扩大堆内存的大小。除此之外,还可能是由于代码问题导致内存消耗过大,例如内存泄漏或是...

Global site tag (gtag.js) - Google Analytics