【问题标题】:Anyone use CFAllocatorSetDefault succesfully in an iPhone app?有人在 iPhone 应用程序中成功使用 CFAllocatorSet Default 吗?
【发布时间】:2013-06-12 16:38:41
【问题描述】:

我希望用我自己的实现替换我的 iPhone 应用程序中的默认 CFAllocator。我想控制UIWebView 分配的内存,因为它在加载网站后似乎保留了这么多内存,而当UIWebView 被释放时,这些内存仍然存在。

在我调用CFAllocatorSetDefault 之后,当下一次分配发生时,我得到一个EXC_BREAKPOINT 异常。

异常似乎发生在对CFRetain 的调用中(在模拟器中完成,但在设备上发生同样的事情):

CoreFoundation`CFRetain:
0x1c089b0:  pushl  %ebp
0x1c089b1:  movl   %esp, %ebp
0x1c089b3:  pushl  %edi
0x1c089b4:  pushl  %esi
0x1c089b5:  subl   $16, %esp
0x1c089b8:  calll  0x1c089bd                 ; CFRetain + 13
0x1c089bd:  popl   %edi
0x1c089be:  movl   8(%ebp), %esi
0x1c089c1:  testl  %esi, %esi
0x1c089c3:  jne    0x1c089db                 ; CFRetain + 43
0x1c089c5:  int3   
0x1c089c6:  calll  0x1d66a00 ; symbol stub for: getpid <- EXC_BREAKPOINT (code=EXC_I386_BPT subcode=0x0)
0x1c089cb:  movl   %eax, (%esp)
0x1c089ce:  movl   $9, 4(%esp)
0x1c089d6:  calll  0x1d66a4e                 ; symbol stub for: kill
0x1c089db:  movl   (%esi), %eax
0x1c089dd:  testl  %eax, %eax
0x1c089df:  je     0x1c08a17                 ; CFRetain + 103
0x1c089e1:  cmpl   1838519(%edi), %eax
0x1c089e7:  je     0x1c08a17                 ; CFRetain + 103
0x1c089e9:  movl   4(%esi), %ecx
0x1c089ec:  shrl   $8, %ecx
0x1c089ef:  andl   $1023, %ecx
0x1c089f5:  cmpl   1834423(%edi,%ecx,4), %eax
0x1c089fc:  je     0x1c08a17                 ; CFRetain + 103
0x1c089fe:  movl   1766575(%edi), %eax
0x1c08a04:  movl   %eax, 4(%esp)
0x1c08a08:  movl   %esi, (%esp)
0x1c08a0b:  calll  0x1d665c8                 ; symbol stub for: objc_msgSend

【问题讨论】:

  • 请注意,WebKit 无论如何都不会使用 CF 的分配器。它有自己的。
  • @Catfish_Man 你确定吗?请参阅我的更新答案。
  • 相当肯定。它可能会使用 CF 的分配器进行一些附带分配,但大部分实际的 WebCore/JSCore 分配使用 FastMalloc。

标签: iphone ios memory-management uiwebview core-foundation


【解决方案1】:

更新

Core Foundation 有一个错误,导致 CFAllocatorSetDefault 无用。

具体来说,如果你研究_CFRuntimeCreateInstanceCFRuntime.c中的实现,你会发现:

  • 如果它没有使用系统默认分配器,它会尝试保留分配器。
  • 如果已将 NULL 作为其 allocator 参数传递,它将尝试保留该 NULL 而不是当前的默认分配器。
  • 因此,对CFRetain 的调用将崩溃。

应该做的是在将NULL 作为其allocator 参数给出时保留当前的默认分配器。

由于 Apple 自己的库中的许多函数显然将 NULL(或 kCFAllocatorDefault,这也是一个空指针)传递给创建 Core Foundation 对象的函数,如果您更改默认值,您肯定会很快崩溃分配器。

我的测试用例:我创建了一个新的单视图 iPhone 应用。我给main加了一行:

int main(int argc, char *argv[])
{
    CFAllocatorSetDefault(kCFAllocatorMalloc);
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

应用程序在模拟器和我的测试设备上启动时崩溃,CFRetainEXC_BREAKPOINT,函数参数为空指针。

原创

您将一个空指针传递给CFRetain。如果这与您的自定义分配器有关,您需要发布更多详细信息,例如发生异常时的完整调用堆栈。

在您的反汇编列表中,从0x1c089b00x1c089bd 的说明是函数序言。

0x1c089bemovl 8(%ebp), %esi 指令将第一个函数参数从堆栈加载到%esi

0x1c089c1testl %esi, %esi 指令根据%esi 的值设置处理器标志。特别是,如果 %esi 包含零,它将 Z(零)标志设置为 1,如果 %esi 包含其他任何内容,则将 Z 标志设置为 0。

0x1c089c3,如果ne 条件为真,则jne 0x1c089db 指令跳转。 ne 条件在 Z 标志为 0 时为真,在 Z 标志为 1 时为假。因此,当%esi(第一个参数)为非零时,该指令跳转,当%esi 为零时跳转。

0x1c089c5 处,int3 指令引发SIGTRAP 信号,异常代码为EXC_BREAKPOINTint3 指令通常在您设置断点时由调试器填充到程序中。在这种情况下,它在编译时被硬编码在程序中。

因此,您收到此异常是因为您将空指针传递给CFRetain

喜欢的也可以看看CFRetain的源码。在CFRuntime.c:

CFTypeRef CFRetain(CFTypeRef cf) {
    if (NULL == cf) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT; }
    if (cf) __CFGenericAssertIsCF(cf);
    return _CFRetain(cf, false);
}

所以CFRetain 做的第一件事就是测试它的参数是否是NULLCGSetCrashLogMessage 是在 CoreFoundation_Prefix.h 中定义的宏,它什么都不做。 HALTCFInternal.h中定义的宏:

    #define HALT do {asm __volatile__("int3"); kill(getpid(), 9); } while (0)

如您所见,HALT 有一个硬编码的int3 指令。然后它调用kill(getpid(), 9)。这与您的反汇编列表相符。

【讨论】:

  • 这是发生异常时的部分堆栈:` frame #0: 0x01c169c6 CoreFoundationCFRetain + 22 frame #1: 0x01c17917 CoreFoundation_CFRuntimeCreateInstance + 391 frame #2: 0x01c202aa CoreFoundation__CFArrayInit + 202 frame #3: 0x01c201d0 CoreFoundation__CFArrayCreateMutable0 + 32 frame #4: 0x035c2e52 WebCore@ @-[WAKView addSubview:] + 102` 原生 CFRetain 被调用,可能不喜欢我的分配器早期创建的东西。
  • 我在bugreport.apple.com 提交了一个错误 (#14185614)。如果你想修复这个问题,你还应该提交一个错误。
  • 这应该在 Mavericks/iOS 7 中修复,fwiw
  • @Catfish_Man 我还可以确认这在 iOS7-9 中完美运行(在 iOS 6 上崩溃)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 2011-05-23
  • 2013-02-19
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
相关资源
最近更新 更多