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 ...
随机推荐
- Enum
1.定义时使用enum关键字定义. 2.隐式继承了java.lang.Enum类,所以不能再继承其他类了. 3.隐式的final修饰符,所以不能被其他类继承. package enumTest; pu ...
- bahuanghou111
#include<stdio.h> int map[8][8]={0}; int count=0; int safe(int x,int y) { int i; int j; for(i= ...
- 提高Baidu Map聚合的效率
百度的MAP的例子里提供了一个聚合效果,地址是http://developer.baidu.com/map/jsdemo.htm#c1_4 ,效果图如下图: 这个效果很赞,但效率很低,当数据量达到50 ...
- log4j使用快速入门【转】
1.引言 在应用程序中添加日志记录总的来说基于三个目的: .监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工作 .跟踪代码运行时轨迹,作为日后审计的依据 .担当集成开发环境中的调 ...
- css基础知识
CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明.其中选择器通常是您需要改变样式的 HTML 元素(比如p标签),也可以是节点的属性的值(比如id,class):每条声明都是一条字典key ...
- 关于sed用法
sed处理流程 sed的处理流程,简化后是这样的: 1.读入新的一行内容到缓存空间: 2.从指定的操作指令中取出第一条指令,判断是否匹配pattern: 3.如果不匹配,则忽略后续的编辑命令,回到第2 ...
- ORM系列之二:EF(4) 约定、注释、Fluent API
目录 1.前言 2.约定 2.1 主键约定 2.2 关系约定 2.3 复杂类型约定 3.数据注释 3.1 主键 3.2 必需 3.3 MaxLength和MinLength 3.4 NotMapped ...
- LeetCode Remove Element
原题链接在这里:https://leetcode.com/problems/remove-element/ 题目: Given an array and a value, remove all ins ...
- docker好文收藏
深入浅出Docker(一):Docker核心技术预览 2. 核心技术预览 Docker核心是一个操作系统级虚拟化方法, 理解起来可能并不像VM那样直观.我们从虚拟化方法的四个方面:隔离性.可配额/可度 ...
- Python_转义字符
转义字符 描述 \(在行尾时) 续行符 \\ 反斜杠符号 \' 单引号 \" 双引号 \a 响铃 \b 退格(Backspace) \e 转义 \000 空 \n 换行 \v 纵向制表符 \ ...