我希望能够在每次分配、保留、释放或解除分配特定CFType
对象(对于我当前的目的, a )时记录消息(最好中断调试器)。CGPDFDocument
因为没有需要a 的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 [...]
在_CFRuntimeCreateInstance()
at #2 调用CFRetain()
上面详述的问题之前。
有人可以帮我理解这里发生了什么(特别是默认分配器如何处理保留和释放,以及为什么我得到 SIGTRAP);如何修复它;以及是否有更好的方法来做我想做的事情?
(我想我可能能够弄清楚如何使用 DTrace 来探测CFRetain()
和,并由forCFRelease()
过滤,但我不知道要探测什么来解除分配(分配并不那么重要,因为我知道它是在 内部完成的)。此外,我更希望能够在保留/释放/解除分配时中断调试器,我认为使用 DTrace 是不可能的。)CFTypeID
CGPDFDocument
CGPDFDocumentCreateWithProvider()
更新:现在阅读了源代码后,CFRelease
我意识到我误解了context.retain
and的目的context.release
——它们是为了保留和释放context.info
. 所以上面描述的整个方法是行不通的。但是,也许 DTrace/Instruments 向导仍然可以发挥一些魔力?!