C++内存泄露之野指针
写出本文仅仅是处于备忘的目的。
最近为现在做的软件添加了一个内存回收机制(以前处于某种内存只申请不释放,这并不等于内存泄露,因为我们知道这些内存块在内存中的位置)-- 在某一块内存不使用的时候将其释放掉,以防止内存缓慢增长。
由于以前没有释放内存,所以就不存在野指针的问题。于是乎肯定坑爹的事情就从内存释放开始了 。。。 /大哭
只从添加了内存释放机制之后软件就出现了各种崩溃 。。。
好了,闲话少说,直奔主题。
一个内存块很多地方引用,一旦一个地方释放内存,而且其他地方还在引用,那后果就 。。。
1.
当时我就想这个问题很简单啊,典型的野指针问题嘛 。。。
于是就给内存块的指针加了个引用计数(引用一次引用计数就加一次(原子操作)),释放内存块时并不是真的释放而是把引用计数减一(原子操作),当引用计数减到0时才会把内存给释放掉 。。。
说道这个各位看客一定以为这个问题就圆满解决了 。 其实 。。。 坑爹的事还没完 才 真正的刚刚开始 。。。 /大哭/大哭/大哭
加了引用计数之后,程序稳定比以前好多了,但是基本上每个1个小时就会崩溃一次 。。。
于是开始各种查找问题 。。。
后来发现问题还是出在资源释放的问题上,请看如下代码:
int Release()
{
InterlockedDecrement(&m_nRefCount); if (m_nRefCount <= 0)
{
delete this;
}
else{
//do something
...
}
return(m_nRefCount);
}
InterlockedDecrement的确是原子操作,但是后面的语句却不是,当多线程存在的时候可能 InterlockedDerement 会被执行两次 之后 第一个 的if 语句才会执行(如果想不明白就好好想,哈哈),这样的问题就是会导致 改内存块被释放两次 。。。
2.
吃一堑长一智 。。。 后来代码改成了这个样子
HRESULT Release()
{
int refCount = InterlockedDecrement(&m_nRefCount); if (refCount <= 0)
{
delete this;
}
else{
//do something
...
}
return(m_nRefCount);
}
这样调用InterlockedDerement之后得到的引用计数就不会受影响了 。。。 至少不会重复delete 自己吧 。。。
3.
这样修改之后软件的确更加稳定啦,运行5-6个小时没问题 。。。 但是 。。。 5-6个小时之后 ,软件依然崩溃,依然崩溃,依然崩溃 。。。
为什么呢?当时也是各种想不通 。。。 后来经过苦思冥想和各种极端调试手段终于发现了问题:
请看我增加引用的方法:
ULONG AddRef( void )
{
return InterlockedIncrement(&m_nRefCount) ;
}
原来我对内存的引用并不是先引用而后释放,而是 引用和释放穿插使用的,由于是多线程,同时增加引用和资源释放并不是互斥执行的,有可能会同时执行,同时执行,同时执行 。。。
当同时执行的时候就会有极小的概率导致引用计数减为0,到delete语句被执行的间隙,存在一次引用计数加一的动作 ,这样内存块看似没有被释放(引用计数为1)其实已经释放了,这样就产生了野指针,产生了野指针,产生了野指针!!!
找到了问题,却不好解决 。。。 因为不能再release和addref里面添加锁,因为使用它的地方太多了,影响效率不说 还可能会导致死锁。
后来只能在可能会出现这种状况的地方添加锁,还好能够产生这种状况的地方不多。
后来问题圆满解决 。。。
C++内存泄露之野指针的更多相关文章
- C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针
C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针 (1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放.造成内存泄露,以下的样 ...
- c/c++:内存泄露和野指针的概念
内存泄漏 用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元.直到程序结束.即所谓内存泄漏. 注意:内存泄漏是指堆内存的泄漏. 简单的说就是申请了一块内存空间,使用 ...
- C/C++中内存泄漏、内存溢出与野指针的解释与说明
1.内存泄漏 内存泄漏是指我们在堆中申请(new/malloc)了一块内存,但是没有去手动的释放(delete/free)内存,导致指针已经消失,而指针指向的东西还在,已经不能控制这块内存, 所以就是 ...
- iOS开发_内存泄漏、内存溢出和野指针之间的区别
今天,在工作群中,被问到了内存泄漏和野指针指向的区别,自己答的不是很好,特意回来查了资料,在博文中总结一下经验,欢迎指正. 内存泄漏:是指在堆区,alloc 或new 创建了一个对象,但是并没有放到自 ...
- Objective-C 【多个对象内存管理(野指针&内存泄漏)】
------------------------------------------- 多个对象内存管理(野指针&内存泄漏) (注:这一部分知识请结合"单个对象内存管理"去 ...
- 七.OC基础加强--1.内存管理 2.野指针,内存泄露 3.set方法的内存管理 4.@property参数 5.@class和循环retain的使用 6.NSString的内存管理
1,内存管理简单介绍 1,为什么要有内存管理? malloc selloc dealloc```需要回头复习 一般的内存 4s 是512m内存:6 是1024m内存: 当内存过大时,会耗尽内存.出现程 ...
- Objective-C 【单个对象内存管理(野指针&内存泄露)】
------------------------------------------- 单个对象内存管理 (1)野指针 ①定义了一个指针变量,但是并没有赋初值,它随机指向一个东西 ②某指针变量指向的内 ...
- 从默认析构函数学习c++,new,delete,内存泄漏,野指针
默认析构函数:当系统没有显式定义析构函数,编译器同样会为对象定义一个默认析构函数,默认的析构函数只能释放普通数据成员所占用的空间,无法通过释放通过new和malloc进行申请的空间,因此避免内存泄漏, ...
- OC-引用计数器,内存管理,野指针
总结 全局断点 →-->+-->Add Exception Breakpoint 开启僵尸监听 打开Edit scheme -->Diagnostics-->Enable Zo ...
随机推荐
- ECMAScript Web APIs node.js
https://hacks.mozilla.org/2015/04/es6-in-depth-an-introduction/ What falls under the scope of ECMASc ...
- MySQL:动态开启慢查询日志(Slow Query Log)
前言 在开发中,高效能的程序 也包括 高效能的查询,所以优化SQL也是程序员必要技能之一.要优化就必须要有慢日志记录才可以知道哪些查询慢,然后反向去修改 慢日志设置方式 写入文件 写入数据库 实践操作 ...
- selenium python的使用(一)
下面是一个爬取知网数据的例子,使用selenium 用python爬取数据 1.创建对象,打开指定地址,在休眠的20秒内输入搜索项 driver= webdriver.Chrome() driver. ...
- 有关windows系统的EXE和DLL文件说法错误
正确答案: B C 你的答案: C (错误) EXE和DLL文件都是PE文件 EXE不能有导出函数,DLL可以有导出函数 EXE有x86和x64之分,则DLL没有 EXE可以单独运行,DLL则不行 ...
- 关于IOS音频的开发积累
1.设置类别,表示该应用同时支持播放和录音 OSStatus error; UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord; ...
- QMap
#include <QCoreApplication> #include<QMap> #include<QDebug> int main(int argc, cha ...
- Spring boot学习一
SSM框架:Spring+SpringMVC+MyBatisSpring Boot一.pom文件:pom.xml中添加: <!--spring-boot-starter-web提供了对we ...
- css ul li 横向排列
因为li是块级元素,默认占一行的,要想实现横向排列,一般通过以下两个方法:float:left这样设置有一个问题,li浮动以后则脱离了文本流,即不占位置,如果它的父级元素有具体的样式且没有固定宽高,建 ...
- CentOS 7 安装 nginx
一.安装nginx依赖lib库: 1.yum install gcc-c++ -y 2.yum install pcre pcre-devel -y 3.yum install zlib zlib-d ...
- 中英文维基百科语料上的Word2Vec实验
最近试了一下Word2Vec, GloVe 以及对应的python版本 gensim word2vec 和 python-glove,就有心在一个更大规模的语料上测试一下,自然而然维基百科的语料进入了 ...