Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3150078
  • 博文数量: 117
  • 博客积分: 10003
  • 博客等级: 上将
  • 技术积分: 5405
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-23 09:34
文章分类

全部博文(117)

文章存档

2011年(1)

2010年(10)

2009年(69)

2008年(37)

分类: LINUX

2008-04-09 12:58:54

下面我举一个常见的例子:

 

在动态库中,我要使用进程中唯一的对象mInstance,标准的写法:

liba.so的代码

static Myclass *mInstance;     //声明一个静态Myclass对象指针。

 

Myclass getInstance()

{

     if(NULL == mInstance)

     {

           mInstance = new Myclass;

      }

      return mInstance;

}

 

上面的代码,大家应该非常熟悉了,而在引入了dlopen之后,有可能会导致内存泄漏。

 

下面,我使用伪代码来说明这个问题。

 

1                         dlopen(liba.so);

2                         pInstance=getInstance();

……………….

3                         dlclose(liba.so);

………………….

4                         dlopen(liba.so);

5                         pInstance=getInstance();

………………….

 

我来解释一下有可能导致的内存泄漏。

1、               加载了动态库liba.so,同时初始化了其数据段,这时mInstance应该为空。

2、               getInstance看到mInstance为空,则在堆中分配了一块内存,生成一个Myclass实例,同时为数据段的mInstance赋值

3、               卸载了动态库liba.so,这时mInstance是不存在的,也就意味着我们丢失了在堆中生成的Myclass对象实例。

4、               加载了动态库liba.so,同时初始化了其数据段,这时mInstance应该为空。

5、               getInstance看到mInstance为空,则在堆中又分配了一块内存,生成一个Myclass实例,同时为数据段的mInstance赋值

 

这样,每做一次这样的时间循环,将会导致一个Myclass对象内存泄漏。

 

这个问题的实质是:

在我们的心目中,一个static的对象的生存周期是贯穿在进程始终的,实际上不是这样。在动态库中的static对象,其生命周期等于该动态库的生命周期。采用静态链接的方式,动态库的生命周期等于进程的声明周期;而采用动态加载的方式,则是不同的。

 

为了避免上面的问题出现,我们要在动态库卸载的时候,释放掉该块内存。

 

有两个方法:

1、  我们写一个释放内存的函数,在调用dlclose之前,调用该函数。

2、  我们在动态库的析构函数中,释放这块内存。

  void __attribute__ ((destructor)) my_fini(void);

在这里我推荐第二个方法,它对不需要上层用户做任何改动,对其完全透明。

阅读(8657) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~