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 ...
随机推荐
- hibernate学习(5)——一对多关系表达
一对多实现 1. 实现类 package com.alice.hibernate02.vo; import java.util.HashSet; import java.util.Set; publi ...
- JavaScript对象属性(一)
对象object 对象和数组很相似,数组是通过索引来访问和修改数据,对象是通过属性来访问和修改数据的. 这是一个示例对象: var cat = { "name": "W ...
- css定位 与position
本文同时发表于本人个人网站 www.yaoxiaowen.com 在正式讨论position之前,我们需要知道几个概念. 块元素:独占一行的元素.比如div,h1~h6,p等,它是自带换行的. 内联元 ...
- CSS3 媒体查询移动设备尺寸 Media Queries for Standard Devices (包括 苹果手表 apple watch)
/* ----------- iPhone 4 and 4S ----------- */ /* Portrait and Landscape */ @media only screen and (m ...
- oracle正则表达式的用法
<SPAN style="FONT-SIZE: 18px">Oracle 正则表达式函数-REGEXP_SUBSTR 使用例子 .5个参数 第一个是输入的字符串 第二个 ...
- Java语言程序设计(基础篇) 第六章 方法
第六章 方法 6.2 定义方法 1.方法的定义由方法名称.参数.返回值类型以及方法体组成. 2.定义在方法头中的变量称为形式参数(formal parameter)或者简称为形参(parameter) ...
- centos 安装redis并加入系统服务
1.安装redis wget http://download.redis.io/releases/redis-3.2.5.tar.gz 解压:tar -zxvf redis-3.2.5.tar.gz ...
- simple_tag,filte,分页以及cookie和装饰器
自定义simple_tag 内置的方法 首先Django中包含了很多内置的方法: 这里通过lower实现 在views视图函数中写如下代码: def tp3(request): name= " ...
- weblogic
停止(2) 更新 原路径 下一步 激活更新 启动(1)
- Sass与Web组件化相关的功能
Sass https://en.wikipedia.org/wiki/Sass_(stylesheet_language) Sass (Syntactically Awesome Stylesheet ...