【发布时间】:2011-07-03 04:58:54
【问题描述】:
我希望能够在每次分配、保留、释放或取消分配特定的 CFType 对象(就我当前的目的,CGPDFDocument)时记录消息(最好中断到调试器)。
因为CGPDFDocument 没有采用CFAllocatorRef 的Create...() 方法,所以我正在尝试像这样临时更改默认分配器:
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 [...]
在#2 的_CFRuntimeCreateInstance() 调用上面详述的有问题的CFRetain() 之前。
有人可以帮我理解这里发生了什么(特别是默认分配器如何处理保留和释放,以及为什么我得到 SIGTRAP);如何解决它;以及是否有更好的方法来做我想做的事情?
(我想我可能会想出如何使用 DTrace 来探测 CFRetain() 和 CFRelease(),通过 CFTypeID 过滤为 CGPDFDocument,但我不知道要探测什么来解除分配(跟踪分配并不那么重要,因为我知道它是在CGPDFDocumentCreateWithProvider() 内完成的。此外,我更希望能够在保留/释放/解除分配时中断调试器,我认为使用 DTrace 是不可能的。 )
更新: 现在阅读了source code 为CFRelease 我意识到我误解了context.retain 和context.release 的目的——它们是为了保留和释放context.info。所以上面描述的整个方法是行不通的。但是,也许 DTrace/Instruments 向导仍然可以发挥一些魔力?!
【问题讨论】:
-
嗨,我有点困惑为 CFAllocatorRef 分配内存。我知道使用 default 和 NULL 创建内存的两种方法,但该内存对于我的应用程序来说是不够的。你能帮我为我的应用程序创建一些手动内存..!!感谢提前
标签: xcode macos ios core-foundation dtrace