本文介绍在基于恒生T2SDK基础上开发对接UFX柜台时,有关引用计数的一些心得体会。
下面以配置接口和连接接口为例子来介绍,下面是文档介绍:
创建配置接口说明:
创建连接接口说明:
文档指出,在使用NewXX类返回的指针时,必须调用AddRef,在不需要使用时,调用Release来释放引用计数。看到这里,心里就有一个疑问,在调用CConnectionInterface* pConnect = NewConnection(lpConfig)
时,lpConfig
的引用计数会增加吗?如果此时增加,那么什么时候释放呢?
原理分析
引用计数往往和一块申请好的内存相互关联,在这块内存被申请者申请后(此处是NewConfig,引用计数为1),传递给其他模块使用(此处为NewConnection的入参)时,需要由其他模块对这块内存维护引用计数。从这个角度出发,NewConnection
操作会增加传入指针的引用计数,而对应的Release
操作,会减少传入指针的引用计数。
实践验证
由于T2SDK
提供的dll未附带调试信息,因此,采用内存对比法来验证调用Release
函数时,是否真的释放内存。为了突出重点,此处只选用NewConfig
和NewConooection
这两个函数来验证。
- 第一步
CConfigInterface * lpConfig = NewConfig(); // 创建配置接口
lpConfig->AddRef();
//lpConfig->AddRef();
lpConfig->Release();
//lpConfig->Release();
方法:观察 lpConfig
所指向的内存有效性来验证释放内存有效性。
结论:AddRef和Release要一对一调用才能正确释放内存,两次AddRef对应一次Release,内存不会释放,一次AddRef对应两次Release,会触发异常。
- 第二步
CConfigInterface * lpConfig = NewConfig(); // 创建配置接口
lpConfig->AddRef();
CConnectionInterface* lpConnect = NewConnection(lpConfig); // 创建连接接口
lpConnect->AddRef();
// 类型1
lpConfig->Release();
lpConfig->Release(); // 调用此句,内存释放,说明 NewConnection 内部在创建成功的情况下,会对入参增加引用计数
// 类型2
lpConnect->Release();
lpConfig->Release();
lpConfig->Release(); // 调用到此处会崩溃,说明调用 lpConnect->Release() 时,会对之前的入参减少引用计数
// 类型3
lpConnect->Release();
lpConnect = NULL;
lpConfig->Release(); // 能够正常释放内存
lpConfig = NULL; // 防止后续代码误用
小结,NewConnection
函数以及其他New类型函数,对传入的NewXXX
类型入参会增加引用计数,调用Release
函数时,会减少对应的引用计数。从语义上来说,调用Release
表明当前模块不再关心该内存内容,以防后续业务代码误用,最好将对应指针置为空。
如果是NewXXX
返回的句柄在后续业务中需要继续使用,那么将此对象保存为成员函数对象,在整个生命周期中都维持有效,直到最终退出时,再释放对应内存。