ユーザークライアントアプリが実行されていないときにユーザークライアントクラスインスタンスがある場合は、リリースするよりも頻繁にユーザークライアントインスタンスを確実に保持します。たとえば、メインドライバクラスのクライアントインスタンスへの保持された参照を保持している場合があります。ユーザークライアントクラスのstop()
メソッドで、必ずそのクライアントインスタンスをドライバーから削除してください。
注意すべきもう1つの点は、オーバーライドされたバージョンの組み込みIOServiceメソッドなどからスーパークラス実装を呼び出すようにすることですstop()
。free()
そうしないと、通常、IOキットが不整合な状態になります。
最後に、I / Oキットドライバーの保持リークをデバッグするための便利な手法は、ログバージョンでメソッドをオーバーライドすることにより、保持とリリースを実際にログに記録することです。
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()
あり、後者をオーバーライドすると、タグ付きバージョン(null以外のタグ付き)を使用するため、OSCollectionsからの保持とリリースは表示されません。taggedRelease()
retain()
release()
によって生成されるバックトレースは、OSReportWithBacktrace()
残念ながら16進ポインターの集まりにすぎませんが、gdbを使用してそれらを検索できます。
いずれの場合も、オブジェクトの保持と解放をログに記録することで、すべての保持を調べて、適切な場所の解放と一致していることを確認できます。サイクルに気をつけろ!