Проверка размера объекта в Objective-C

#ios #memory-management

#c #objective-c #sizeof

Вопрос:

Я пытаюсь определить размер объекта objective-c. Я использую что-то похожее на:

     NSLog(@"sizeof myObject: %ld", sizeof(*myObject));
  

Однако это просто дает мне размер указателя.

Что я делаю не так?

Комментарии:

1. Каков тип MyObject?

2. В данном случае это NSDictionary с произвольным количеством ключей и значений.

3. Скорее всего, потому, что NSDictionary действительно является непрозрачным дескриптором сложной структуры данных. Посмотрите ваши заголовки (у меня нет под рукой Mac, так что извините).

4. Это потому, что объект — это, по сути, просто структура с указателем на структуру класса объекта, и все. Среда выполнения фактически выделяет память для объекта и размещает его внутренние данные.

Ответ №1:

Все, о чем знает компилятор, — это указатель, вот почему вы получаете размер указателя обратно. Чтобы увидеть размер выделенного объекта, используйте один из следующих фрагментов кода:

С помощью ARC:

 #import <malloc/malloc.h>

// ...

NSLog(@"Size of %@: %zd", NSStringFromClass([myObject class]), malloc_size((__bridge const void *) myObject));
  

Без ARC:

 #import <malloc/malloc.h>

// ...

NSLog(@"size of myObject: %zd", malloc_size(myObject));
  

У Майка Эша есть достойный отзыв о некоторых внутренних компонентах среды выполнения Obj-C в его блоге вопросов и ответов:http://mikeash.com/?page=pyblog/friday-qa-2009-03-13-intro-to-the-objective-c-runtime.html

Комментарии:

1. Следует отметить, что большинство классов также сохраняют свое состояние в объектах, на которые они ссылаются с помощью указателей. Они будут выделены отдельно от класса (например, NSString — это структура, которая содержит указатель isa, указатель на буфер, выделенный через malloc, и некоторые другие данные)

2. Да, но в этом случае размер самой структуры объекта не изменяется. Это то же самое, что и любая структура, которая имеет указатель в качестве одного из своих членов. Это также имело бы место для любых ivar, которые также являются объектами.

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

4. Если вы используете ARC, используйте вместо этого этот код (однако не забудьте импортировать malloc.h!): NSLog(@"Size of %@: %zd", NSStringFromClass([myObject class]), malloc_size((__bridge const void *) myObject));

Ответ №2:

В среде выполнения GNU Objective-C вы можете использовать (вы должны импортировать <objc/objc-api.h> :

 class_get_instance_size ([MyClass class]);
  

В Mac OS X вы можете использовать (возможно, потребуется импортировать <objc/runtime.h> ):

 class_getInstanceSize ([MyClass class]);
  

Эти функции вернут, сколько памяти требуется для выделения объекта, это не будет включать память, выделенную объектом при его инициализации.

Комментарии:

1. Просто в качестве примечания, class_getInstanceSize доступен только в версии 10.5

Ответ №3:

Прежде всего, я думаю, из приведенных выше сообщений ясно, что размер объекта задается с помощью malloc_size (MyObject), как предложено Джейсоном, а также в справочном руководстве Mac OS:

«Функция malloc_size(ptr) возвращает размер блока памяти, который поддерживает выделение, на которое указывает ptr. Размер блока памяти всегда, по крайней мере, такой же большой, как выделение, которое он поддерживает, и может быть больше.» ( http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/malloc_size.3.html )

Но если вам интересно узнать размер словаря, имейте в виду следующий момент:

Словарь хранит пары ключ-значение и не содержит сам объект в части значения, а просто увеличивает количество сохраняемых объектов, которые должны были быть «добавлены», и сохраняет ссылку на этот объект при себе. Теперь сам словарь просто содержит ссылки на различные объекты (с прикрепленным ключом). Итак, если вы случайно ищете размер объекта для всех объектов, на которые ссылается словарь, технически это не будет размером словаря. Размер словаря был бы суммой размера всех ключей плюс размер всех ссылок на значения по отношению к ключам плюс размер родительского NSObject. Если вы все еще заинтересованы в определении размера указанных объектов, попробуйте выполнить итерацию по массиву значений словаря:

 NSArray *myArray = [myDictionary allValues];
id obj = nil;
int totalSize = 0;
for(obj in myArray)
{
    totalSize  = malloc_size(obj);
}
//totalSize now contains the total object size of the refered objects in the dictionary.
  

Надеюсь, это ответ на вопрос.

Комментарии:

1. Как насчет ключей? На самом деле NSDictionary реализует свой ключ с помощью NSCopying протокола.

Ответ №4:

Размер объекта (objective-c) нелегко найти, потому что его даже нелегко определить. Что вы имели в виду, говоря «размер объекта objective-c»?

Размер ссылки равен размеру указателя (возвращаемого sizeof(obj_ref)).

Размер памяти, который был выделен при создании ( alloc), можно определить по способу, указанному Джейсоном в первом ответе. Но это зависит от среды выполнения. gnu-runtime отличается от apple-runtime. В конечном итоге это только та память, которая необходима для примитивных типов данных, из которых состоит экземпляр. Но не памяти, которая может быть выделена позже (т. Е. во время инициализации (-init)) для объектов, на которые ссылаются переменные или строки.

Экземпляр класса

 @interface FirstClass
{
    int _someInt;
    char _someChar;
}
…
@end
  

требуется не менее 5 байт (во многих системах — int размер может отличаться) плюс статические издержки, если это необходимо для среды выполнения. Размер такого объекта очевиден.

Но для экземпляра класса

 @interface SecondClass
{
    FirstClass *_someObject;
    char *_name;
    id _data;
}
…
@end
  

определение «размера» является сложным. Объекту требуется 12 байт (в 32-разрядных системах) плюс накладные расходы на выделение. Но, возможно, имя является частью объекта и выделяется / освобождается им. Должна ли память, в которой требуется фактическое имя, быть частью размера объекта? А как насчет объектов, на которые ссылаются?

Комментарии:

1. Не забудьте добавить 4/8 байта к каждому объекту для указателя isa, который потребуется в обеих средах выполнения.

Ответ №5:

Я бы предложил использовать class_getInstanceSize и malloc_good_size , чтобы посмотреть, до чего он будет округляться. При этом не будут отображаться переменные и еще много чего внутри возвращаемого размера.

 #import <malloc/malloc.h>
#import <objc/runtime.h>

NSLog(@"Object Size: %zd", malloc_good_size(class_getInstanceSize([yourObject class])));
  

Ответ №6:

Я думаю, что описание класса содержит информацию о размере — лучше посмотреть это, чем запрашивать с помощью sizeof оператора.