我希望每次分配,保留,释放或取消分配特定CFType
对象(当前用途,CGPDFDocument
)时,都能记录消息(最好是中断到调试器)
因为Create...()
没有CGPDFDocument
方法需要CFAllocatorRef
,所以我试图像这样暂时更改默认分配器:
void MyPDFDocumentCreate()
{
// ...
CFAllocatorRef defaultAllocator = CFAllocatorGetDefault();
CFAllocatorSetDefault(MyLogAllocator());
CGPDFDocumentRef documentRef = CGPDFDocumentCreateWithProvider(provider);
CFAllocatorSetDefault(defaultAllocator);
// ...
}
其中MyLogAllocator()
的定义如下:
static void *(*DefaultAllocate)(CFIndex size, CFOptionFlags hint, void *info);
static const void *(*DefaultRetain)(const void *info);
static void (*DefaultRelease)(const void *info);
void *LogAllocate(CFIndex size, CFOptionFlags hint, void *info)
{
fprintf(stderr, "LogAllocate %p", info);
if (DefaultAllocate)
return DefaultAllocate(size, hint, info);
else
return NULL;
}
const void *LogRetain(const void *info)
{
fprintf(stderr, "LogRetain");
if (DefaultRetain)
return DefaultRetain(info);
else
return info;
}
void LogRelease(const void *info)
{
fprintf(stderr, "LogRelease");
if (DefaultRelease)
DefaultRelease(info);
}
static CFAllocatorRef MyLogAllocator()
{
static CFAllocatorRef theLogAllocator = NULL;
if (!theLogAllocator)
{
CFAllocatorContext context;
CFAllocatorRef defaultAllocator = CFAllocatorGetDefault();
CFAllocatorGetContext(defaultAllocator, &context);
DefaultAllocate = context.allocate;
DefaultRetain = context.retain;
DefaultRelease = context.release;
context.allocate = LogAllocate;
context.retain = LogRetain;
context.release = LogRelease;
theLogAllocator = CFAllocatorCreate(kCFAllocatorUseContext, &context);
}
return theLogAllocator;
}
但是,似乎默认分配器(kCFAllocatorSystemDefault
据我所知)对于context.retain和context.release都有NULL,所以我没有任何原始实现来调用。这可能是为什么,当我尝试上面的代码时,我得到以下堆栈跟踪:
#0 0x357ded12 in CFRetain ()
#1 0x357dcb68 in _CFRuntimeCreateInstance ()
#2 0x303fe35e in CGTypeCreateInstanceWithAllocator ()
#3 0x303fe34c in CGTypeCreateInstance ()
#4 0x304b32f4 in CGPDFDocumentCreateWithProvider ()
#5 0x000293f4 in MyPDFDocumentCreate ([...]) at [...]
XCode实际上并没有告诉我为什么会停止,但如果我继续尝试,我会得到:
(gdb) continue
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x357ded12 in CFRetain ()
(gdb) continue
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x357ded12 in CFRetain ()
(gdb)
然而,我继续多次,我得到相同的SIGTRAP。我不知道如何解释它;我设置的唯一断点是objc_exception_throw
上的象征性断点。
有一点需要注意的是,LogRetain()
和LogAllocate()
每次都被CFAllocatorCreate()
成功调用一次(按此顺序):
#0 LogRetain (info=0x1a8000) at [...]
#1 0x358086f2 in CFAllocatorCreate ()
#2 0x00028d58 in MyLogAllocator () at [...]
#3 0x000293e0 in MyPDFDocumentCreate ([...]) at [...]
#0 LogAllocate (size=104, hint=0, info=0x1a8000) at [...]
#1 0x3580882e in CFAllocatorCreate ()
#2 0x00028d58 in MyLogAllocator () at [...]
#3 0x000293e0 in MyPDFDocumentCreate ([...]) at [...]
然后LogAllocate()
再次成功CFAllocatorAllocate()
:
#0 LogAllocate (size=64, hint=1024, info=0x1a8000) at [...]
#1 0x357dcc06 in CFAllocatorAllocate ()
#2 0x357dcb04 in _CFRuntimeCreateInstance ()
#3 0x303fe35e in CGTypeCreateInstanceWithAllocator ()
#4 0x303fe34c in CGTypeCreateInstance ()
#5 0x304b32f4 in CGPDFDocumentCreateWithProvider ()
#6 0x000293f4 in MyPDFDocumentCreate ([...]) at [...]
在#{1}}#2之前调用上面详述的有问题的_CFRuntimeCreateInstance()
。
有人可以帮我理解这里发生了什么(尤其是默认分配器如何处理保留和释放,以及为什么我要获得SIGTRAP);如何解决它;以及是否有更好的方法来做我想做的事情?
(我想我可能会弄清楚如何使用DTrace来探测CFRetain()
和CFRetain()
,CFRelease()
为CFTypeID
过滤,但我不会知道如何调用deallocation(分配不是那么重要,因为我知道它在CGPDFDocument
内完成)。而且,我更愿意能够在retain / release / deallocate上打破调试器,我认为使用DTrace是不可能的。)
更新:现在阅读CGPDFDocumentCreateWithProvider()
的{{3}}我意识到我误解了CFRelease
和context.retain
的目的 - 他们是保留和释放context.release
。所以上面描述的整个方法都是非首发的。但是,也许DTrace / Instruments向导可能仍然可以运用一些魔法?!
答案 0 :(得分:0)
这是一个非常有趣的问题。由于您已经深入研究过滤DTrace,并且您正在深入了解CFRelease
源,那么您可以查看使用gdb断点条件来选择何时中断。要确定是否要进行释放,只需使用CFGetRetainCount()
。
那就是说,我猜你是在拉着你的头发追踪一些过度释放的崩溃,对吧?要查看的内容可能比逆向工程CFRelease()
更有用: