【问题标题】:Why the NSNumber *test = [NSNumber numberWithInt:i] does not add memory footprint in a for loop?为什么 NSNumber *test = [NSNumber numberWithInt:i] 不会在 for 循环中添加内存占用?
【发布时间】:2015-08-19 14:48:37
【问题描述】:

我试图在 for 循环中重现巨大的内存占用。例如,在下面的 for 循环中,如果其中没有自动释放池。这将导致峰值内存占用。

for(int i=0; i< 500000; i++){
    NSNumber *test = [NSNumber numberWithInt:i];
}

因为表达式[NSNumber numberWithInt:i]返回一个自动释放对象,如果for循环中没有自动释放,所有自动释放的对象都会被释放一次,这会导致内存占用峰值。
但正如我在 Xcode6 中测试的那样,这个结果并没有重现。我用这个totalSize += malloc_size((__bridge const void *) test); 来计算所有对象的总大小,但我得到了totalSize = 0 结果。
我可以使用[NSString stringWithFormat:@"%d ", i]; 之类的代码重现巨大的内存占用。
谁能解释一下这个问题,提前谢谢。

【问题讨论】:

    标签: ios objective-c memory


    【解决方案1】:

    NSNumbers(适合60位的)存储为标记指针。它是携带数值的实际 64 位指针值,因此没有进行堆分配。这由 Obj-C 运行时为您透明地完成。 有关此主题的更多信息:https://mikeash.com/pyblog/friday-qa-2012-07-27-lets-build-tagged-pointers.html

    NSString 也存储为标记指针。请参阅 Mike Ash 关于标记指针字符串的优秀文章:https://mikeash.com/pyblog/friday-qa-2015-07-31-tagged-pointer-strings.html

    【讨论】:

    • 非常感谢您的帮助!
    【解决方案2】:

    在您粘贴的 for 循环中,test 变量被创建并立即销毁。
    它属于 for 的范围,因为没有其他东西从外部引用它,所以它会在循环结束时由 ARC 自动释放。
    这就是为什么你的内存占用没有增长的原因。

    【讨论】:

    • 这通常是正确的答案,而且 ARC 也很聪明,但在这种特殊情况下,Tamás Zahola 的答案更适用。
    • 这在 C++ 中是正确的,其中堆栈对象在离开当前范围时被释放。然而在 Obj-C 中,自动释放的对象在离开当前的自动释放池时被释放,这是一个单独的野兽。
    • (我是说有一个优化技巧可以避免自动释放池,但我可能在想objc_retainAutoreleasedReturnValue,它解决了另一个问题。@TamásZahola 在这里可能完全正确。)
    • 看看使用 [NSNumber numberWithLong:LONG_MAX - i] 是否会走常规的自动释放路线,或者 ARC 是否有其他避免自动释放池的方法会很有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    相关资源
    最近更新 更多