zoukankan      html  css  js  c++  java
  • 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里面添加锁,因为使用它的地方太多了,影响效率不说 还可能会导致死锁。

    后来只能在可能会出现这种状况的地方添加锁,还好能够产生这种状况的地方不多。

    后来问题圆满解决 。。。 

  • 相关阅读:
    kubernetes概述与入门
    kubernetes入门到放弃-docker基础篇
    Git远程仓库☞GitLab的使用
    Git远程仓库☞GitHub的使用
    Git版本控制系统
    持续集成-DevOps概念篇
    持续集成扫盲篇
    Centos7系统介绍
    LNMP架构说明
    dynamic_cast c++
  • 原文地址:https://www.cnblogs.com/Haijunzhu/p/4943249.html
Copyright © 2011-2022 走看看