如果您在没有用户客户端应用程序运行时拥有用户客户端类实例,那么您肯定会更频繁地保留用户客户端实例而不是发布它们。例如,您可能会在主驱动程序类中保留对客户端实例的保留引用。在您的用户客户端类的stop()
方法中,确保从驱动程序中删除该客户端实例。
另一件需要注意的事情:确保从内置 IOService 方法(例如 等)的覆盖版本调用超类实现stop()
。free()
不这样做通常会使 IO Kit 进入不一致的状态。
最后,在 I/O Kit 驱动程序中调试保留泄漏的一个有用技术是通过使用日志版本覆盖方法来实际记录保留和释放:
void MyClass::taggedRetain(const void* tag) const
{
OSReportWithBacktrace(
"MyClass" CLASS_OBJECT_FORMAT_STRING "::taggedRetain(tag=%p)\n", CLASS_OBJECT_FORMAT(this), tag);
IOService::taggedRetain(tag);
}
void MyClass::taggedRelease(const void * tag) const
{
OSReportWithBacktrace(
"MyClass" CLASS_OBJECT_FORMAT_STRING "::taggedRelease(tag=%p)\n", CLASS_OBJECT_FORMAT(this), tag);
int count = getRetainCount();
IOService::taggedRelease(tag);
if (count == 1)
printf(
"MyClass::taggedRelease(tag=%p) final done\n", tag);
else
printf(
"MyClass" CLASS_OBJECT_FORMAT_STRING "::taggedRelease(tag=%p) done\n", CLASS_OBJECT_FORMAT(this), tag);
}
此代码中的宏在标头中定义如下:
#define CLASS_OBJECT_FORMAT_STRING "[%s@%p:%dx]"
#define CLASS_OBJECT_FORMAT(obj) myClassName(obj), obj, myRefCount(obj)
inline int myRefCount(const OSObject* obj)
{
return obj ? obj->getRetainCount() : 0;
}
inline const char* myClassName(const OSObject* obj)
{
if (!obj) return "(null)";
return obj->getMetaClass()->getClassName();
}
#endif
我应该解释一下taggedRetain()
and是andtaggedRelease()
的实际底层实现- 如果您覆盖后者,您将不会看到来自 OSCollections 的任何保留和释放,因为它们使用标记版本(带有非空标记)。retain()
release()
不幸的是,生成的回溯OSReportWithBacktrace()
只是一堆十六进制指针,但您可以使用 gdb 查找它们。
在任何情况下,通过记录对象的保留和释放,您可以检查所有保留并确保它们与正确位置的释放相匹配。注意循环!