【问题标题】:Using NSAutoreleasePool only via Objective-C runtime functions仅通过 Objective-C 运行时函数使用 NSAutoreleasePool
【发布时间】:2019-06-22 21:32:55
【问题描述】:

我正在学习如何在 Objective-C 中进行内存管理。据我所知,标记为autorelease 的对象将被添加到封闭的NSAutoreleasePool 中,并在池被释放/耗尽时被释放。

为了尝试我的新知识,我创建了一些测试;创建 100 万个对象使用 ~17mb,创建相同的对象但立即释放它们使用 ~1mb。但是,我无法让NSAutoreleasePool 工作,使用下面的代码仍然使用 ~17mb,我不明白为什么。

#include <objc/objc-runtime.h>
#include <stdio.h>

int main(void) {
    Class NSAutoreleasePool = objc_getClass("NSAutoreleasePool");
    Class Object = objc_getClass("NSObject");
    SEL new = sel_registerName("new");
    SEL drain = sel_registerName("drain");
    SEL autorelease = sel_registerName("autorelease");
    id pool = objc_msgSend(NSAutoreleasePool, new);
    for (int i = 0; i < 1e6; i++) {
        id obj = objc_msgSend(Object, new);
        objc_msgSend(obj, autorelease);
    }
    objc_msgSend(pool, drain);
    printf("OK\n");
    getchar();
    return 0;
}

【问题讨论】:

  • 你没有为此使用任何 Objective-C 语法有什么原因吗?你真的想要纯C代码吗?如果是这样,请参阅stackoverflow.com/questions/10289890/… 了解相关信息。
  • @rmaddy 不是。我可以让这个例子在简单的objective-c中工作,但我很好奇为什么它在只使用运行时并从常规C编译时不起作用。我做错了什么还是这种行为是预期的?您链接的问题也没有解决这个问题。接受的答案还声称 NSAutoreleasePool 已被弃用,苹果文档没有说明。
  • 你确定这些电话实际上是在返回任何东西吗?即,您是否与基金会有关联?
  • @JoshCaswell 是的,NSObjectNSAutoreleasePool 都是有效对象(是的,我已链接到基金会)
  • 有趣...感谢您的确认。

标签: objective-c foundation objective-c-runtime nsautoreleasepool


【解决方案1】:

当您在创建每个对象后立即release 时,一次只存在一个对象。因此运行时可以为每个新对象回收相同的内存。运行时只需要向操作系统请求足够的内存来保存那个对象。

当您在创建每个对象后autorelease 时,每个对象都会一直存在,直到自动释放池耗尽,因此您最终会同时存在 1,000,000 个对象。运行时必须要求操作系统提供足够的内存来保存所有对象。而且由于运行时事先不知道您打算创建多少对象,它会逐步向操作系统询问内存块。也许它要求 1 MiB,当 1 MiB 用完时,它又要求 1 MiB,依此类推。

通常,当您的程序释放一些内存(在这种情况下是因为它破坏了一个对象)时,运行时不会将该内存返回给操作系统。它保持内存可用,以便下次创建对象时可以重用它。

操作系统知道它为您的进程分配了多少内存,但它不知道该内存的哪些部分(在进程中)认为“正在使用”,哪些部分被认为“空闲”。

Activity Monitor 和top 都向操作系统询问有关您的进程的信息。所以他们只知道操作系统知道什么,也就是给你的进程分配了多少内存。他们不知道有多少内存在使用,有多少是空闲的。

如果您想更准确地了解程序中活动对象使用了多少内存,则需要使用更具侵入性的工具。 Xcode 附带的 Instruments 程序可以使用 Allocations 工具向您显示“实时分配”正在使用多少内存。

这是分配工具显示的内容,当我在它下运行您的程序大约三秒钟时:

因此,您可以看到 Allocations 工具总共检测到 1,001,983 个“瞬态”分配。瞬态分配是在 Instruments 停止记录之前分配然后释放的一块内存。

您还可以看到,分配的“持久”字节(即在 Instruments 停止记录时已分配且未释放的内存)为 506 KiB,但分配的总字节数(包括后来释放的字节)为 23.5 MiB。

【讨论】:

  • 啊,它的行为是正确的,谢谢!也感谢你告诉我 Instruments,它看起来真的很有用,我相信我将来会使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
  • 2021-01-21
  • 2010-12-19
相关资源
最近更新 更多