仅通过Objective-C运行时函数使用NSAutoreleasePool

时间:2019-01-29 17:21:11

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

我正在学习内存管理在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;
}

1 个答案:

答案 0 :(得分:4)

release制作后立即每个对象,从未有多于一个的对象存在于一个时间。因此,运行时可以为每个新对象回收相同的内存。运行时只需要向操作系统请求足够的内存来容纳该对象。

autorelease创建后的每个对象,每个对象的生命,直到自动释放池被排出,所以你最终同时存在百万对象。运行时必须要求操作系统有足够的内存来容纳所有对象。而且由于运行时无法预先知道要创建多少个对象,因此它会向操作系统递增地请求内存块。也许它要求1 MIB,并且当该1 MIB耗尽,它要求另一个1 MIB,等等。

通常,当你的程序释放一些存储器(在这种情况下,因为它破坏的对象),则运行时不会内存返回到操作系统。它使内存保持可用状态,以便下次创建对象时可以重复使用。

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

活动监视器和top都向操作系统询问有关您的过程的信息。因此他们只知道操作系统知道什么,即已为您的进程分配了多少内存。他们不知道有多少内存正在使用,有多少空闲。

如果你想要多少内存是在你的程序活动对象使用一个更准确的图片,你需要使用一个更具侵入性的工具。该仪器的程序,其自带的Xcode,可以告诉你多少内存在使用中通过“实时分配”使用分配的工具。

下面就是该分配仪器显示,当我运行在它之下你的程序约三秒钟:

Allocations instrument

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

您还可以看到分配的“持久”字节(是分配的内存,并且在仪器停止记录时未释放)为506 KiB,但是分配的总字节(包括以后释放的字节)为23.5 MiB。 p>