卸载ACE动态库导致句柄泄漏问题

ACE动态库在windows程序中通过LoadLibrary和FreeLibrary反复加载和卸载后,发现内存和句柄上涨严重,查看动态库的dllmain函数,发现未调用到ace初始化方法ACE::init(),因此加载动态库后,显式调用init,卸载前显式fini,内存和句柄果然就没有涨了,但出现了一个新问题,在加载到500多次以后,出现了动态库文件无法打开错误,通过更新ACE最新的6.2.0版本的库,发现问题依然存在!

前面成功的500多次加载和卸载ace库,都未看到句柄或者内存泄露现象,突然出现不能加载,问题开始有点难以理解了。

查看ace初始化函数的实现代码,包含了对对象管理器单例对象的初始化操作:

int
ACE::init (void)
{
  // Don't use ACE_TRACE, because Object_Manager might not have been
  // instantiated yet.
  // ACE_TRACE ("ACE::init");

  ++ACE::init_fini_count_;

  return ACE_Object_Manager::instance ()->init ();
}


到ACE_Object_Manager::init里注释代码,也未果;由于每次都是在500多次加载后失败,因此尝试init后不调用fini,果然到100多次后问题就出现了,看来还是和资源未释放完全相关的。在退出函数fini里注释代码,希望能定位到影响问题出现概率的那行代码从而找到相关的资源信息,把fini函数如下代码注释后,问题概率加大:

      // Close the main thread's TSS, including its Log_Msg instance.
      ACE_OS::cleanup_tss (1 /* main thread */);

很快可以想到是tss资源泄漏了,通过在tss资源申请的系统函数TlsAlloc里增加断点,定位到资源申请的位置:

 	ACEd.dll!ACE_OS::thr_keycreate_native(unsigned long * key=0x00ab6220, void (void *)* dest=0x00000000)  Line 4791	C++
 	ACEd.dll!ACE_OS::thr_keycreate(unsigned long * key=0x00ab6220, void (void *)* dest=0x00000000)  Line 4835 + 0xd bytes	C++
 	ACEd.dll!ACE_Thread::keycreate(unsigned long * keyp=0x00ab6220, void (void *)* destructor=0x00000000)  Line 23 + 0xd bytes	C++
 	ACEd.dll!ACE_Threading_Helper::ACE_Threading_Helper()  Line 43 + 0xb bytes	C++
 	ACEd.dll!ACE_Service_Config::ACE_Service_Config(bool ignore_static_svcs=true, unsigned int size=1024, int signum=0)  Line 372 + 0x6d bytes	C++
>	ACEd.dll!ACE_Singleton::ACE_Singleton()  Line 15	C++
 	ACEd.dll!ACE_Unmanaged_Singleton::ACE_Unmanaged_Singleton()  Line 19 + 0x16 bytes	C++
 	ACEd.dll!ACE_Unmanaged_Singleton::instance()  Line 184 + 0x27 bytes	C++
 	ACEd.dll!ACE_Service_Config::singleton()  Line 327	C++
 	ACEd.dll!ACE_Service_Config::current()  Line 424 + 0x5 bytes	C++
 	ACEd.dll!ACE_Service_Config::instance()  Line 87	C++
 	ACEd.dll!ACE_Service_Config::insert(ACE_Static_Svc_Descriptor * stsd=0x102609bc)  Line 332 + 0x9 bytes	C++
 	ACEd.dll!ACE_Static_Svc_ACE_Naming_Context::ACE_Static_Svc_ACE_Naming_Context()  Line 650 + 0x18 bytes	C++
 	ACEd.dll!`dynamic initializer for 'ace_static_svc_ACE_Naming_Context''()  Line 650 + 0xd bytes	C++

以及:

 	ACEd.dll!ACE_OS::thr_keycreate_native(unsigned long * key=0x00ab9648, void (void *)* dest=0x1000b2ad)  Line 4791	C++
 	ACEd.dll!ACE_OS::thr_keycreate(unsigned long * key=0x00ab9648, void (void *)* dest=0x1000b2ad)  Line 4835 + 0xd bytes	C++
>	ACEd.dll!ACE_TSS_Cleanup::tss_keys()  Line 993 + 0x14 bytes	C++
 	ACEd.dll!ACE_TSS_Cleanup::thread_use_key(unsigned long key=7)  Line 941 + 0xc bytes	C++
 	ACEd.dll!ACE_OS::thr_setspecific(unsigned long key=7, void * data=0x00ab9688)  Line 5049	C++
 	ACEd.dll!ACE_Thread::setspecific(unsigned long key=7, void * value=0x00ab9688)  Line 42 + 0xd bytes	C++
 	ACEd.dll!ACE_Threading_Helper::set(void * p=0x00ab9688)  Line 54 + 0xf bytes	C++
 	ACEd.dll!ACE_Service_Config::ACE_Service_Config(bool ignore_static_svcs=true, unsigned int size=1024, int signum=0)  Line 386	C++
 	ACEd.dll!ACE_Singleton::ACE_Singleton()  Line 15	C++
 	ACEd.dll!ACE_Unmanaged_Singleton::ACE_Unmanaged_Singleton()  Line 19 + 0x16 bytes	C++
 	ACEd.dll!ACE_Unmanaged_Singleton::instance()  Line 184 + 0x27 bytes	C++
 	ACEd.dll!ACE_Service_Config::singleton()  Line 327	C++
 	ACEd.dll!ACE_Service_Config::current()  Line 424 + 0x5 bytes	C++
 	ACEd.dll!ACE_Service_Config::instance()  Line 87	C++
 	ACEd.dll!ACE_Service_Config::insert(ACE_Static_Svc_Descriptor * stsd=0x102609bc)  Line 332 + 0x9 bytes	C++
 	ACEd.dll!ACE_Static_Svc_ACE_Naming_Context::ACE_Static_Svc_ACE_Naming_Context()  Line 650 + 0x18 bytes	C++
 	ACEd.dll!`dynamic initializer for 'ace_static_svc_ACE_Naming_Context''()  Line 650 + 0xd bytes	C++
 	msvcr90d.dll!0045c02c() 	

通过观察,发现第二次申请的tss资源在fini函数调用后并没有释放掉,导致tss资源出现了泄漏,申请代码如下:

ACE_TSS_Keys *
ACE_TSS_Cleanup::tss_keys ()
{
  if (this->in_use_ == ACE_OS::NULL_key)
    {
      ACE_TSS_CLEANUP_GUARD
      // Double-check;
      if (in_use_ == ACE_OS::NULL_key)
        {
          // Initialize in_use_ with a new key.
          if (ACE_OS::thr_keycreate (&in_use_,
                                     &ACE_TSS_Cleanup_keys_destroyer))
            {
              ACE_ASSERT (false);
              return 0; // Major problems, this should *never* happen!
            }
        }
    }

因此,一个解决的办法就是在Cleanup的析构函数中,将in_use_对应的tss资源释放:

ACE_TSS_Cleanup::~ACE_TSS_Cleanup (void)
{
    free_key(in_use_);
    in_use_ = 0;
}

重新编译ACE库后,经过长时间测试问题不再出现!












你可能感兴趣的:(网络管理,编程语言)