Использование NSAutoreleasePool только через функции времени выполнения Objective C - PullRequest
0 голосов
/ 29 января 2019

Я изучаю, как работает управление памятью в Objective-C.Из того, что я узнал, объекты, помеченные autorelease, будут добавлены во вложенную NSAutoreleasePool и будут освобождаться всякий раз, когда пул освобождается / сливается.

Чтобы проверить свои новые знания, я создал несколько тестов;Создание 1 миллиона объектов заняло ~ 17 МБ, создание тех же объектов, но немедленное освобождение их - ~ 1 МБ.Тем не менее, я не могу заставить NSAutoreleasePool работать, используя приведенный ниже код все еще использует ~ 17 МБ, и я не понимаю, почему.

#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 голосов
/ 29 января 2019

Когда вы release каждый объект сразу после его создания, никогда не существует более одного объекта одновременно.Таким образом, среда выполнения может перерабатывать одну и ту же память для каждого нового объекта.Среда выполнения должна только запросить у операционной системы достаточно памяти для хранения этого одного объекта.

Когда вы autorelease каждый объект после его создания, каждый объект живет до тех пор, пока пул авто-выпуска не будет исчерпан, так что вы в конечном итоге получите1 000 000 объектов, существующих одновременно.Среда выполнения должна запрашивать у операционной системы достаточно памяти для хранения всех объектов.А поскольку среда выполнения не знает заранее, сколько объектов вы намереваетесь создать, она постепенно запрашивает у операционной системы куски памяти.Возможно, он запрашивает 1 МБ, а когда этот 1 МБ исчерпан, он запрашивает еще 1 МБ и т. Д.

Как правило, когда ваша программа освобождает некоторую память (в данном случае, потому что она уничтожает объект)среда выполнения не возвращает эту память операционной системе.Он сохраняет доступную память, поэтому он может использовать ее в следующий раз, когда вы создаете объект.

Операционная система знает, сколько памяти она дала вашему процессу, но не знает, какие части этой памяти(в рамках процесса) учитывайте «в использовании» и какие части считаются «свободными».

Activity Monitor и top оба запрашивают у операционной системы информацию о вашем процессе.Таким образом, они знают только то, что знает операционная система, то есть сколько памяти было выделено вашему процессу.Они не могут знать, сколько этой памяти используется и сколько свободно.

Если вы хотите получить более точную картину того, сколько памяти используется живыми объектами в вашей программе, вам нужно использоватьболее инвазивный инструмент.Программа Instruments, которая поставляется с XCode, может показать вам, сколько памяти используется «живым распределением» с использованием инструмента Allocations.

Вот что показывает инструмент Allocations, когда я запускаю вашу программу под ним примернотри секунды:

Allocations instrument

Таким образом, вы можете видеть, что инструмент Allocations обнаружил в общей сложности 1 001 983 «переходных» распределений.Временное распределение - это фрагмент памяти, который был выделен и затем освобожден до того, как инструменты прекратили запись.

Вы также можете видеть, что «постоянные» байты распределены (то есть память выделена и не освобождена к моменту, когда инструменты прекратили запись) составляет 506 КБ, но общее количество выделенных байтов (включая освобожденные байты) составляет 23,5 МБ.

...