Подтвердить что ты не робот

Почему ARC сохраняет аргументы метода?

При компиляции с ARC аргументы метода часто оказываются сохраненными в начале метода и выпущены в конце. Эта пара с сохранением/выпуском кажется излишней и противоречит идее, что ARC "выдает код, который вы все равно писали". Никто в те темные дни до ARC не выполнял дополнительный удержание/освобождение по всем аргументам метода только для того, чтобы быть в безопасности, не так ли?

Рассмотрим:

@interface Test : NSObject
@end

@implementation Test

- (void)testARC:(NSString *)s
{
  [s length];  // no extra retain/release here.
}

- (void)testARC2:(NSString *)s
{
  // ARC inserts [s retain]
  [s length];
  [s length];
  // ARC inserts [s release]
}

- (void)testARC3:(__unsafe_unretained NSString *)s
{
  // no retain -- we used __unsafe_unretained
  [s length];
  [s length];
  // no release -- we used __unsafe_unretained
}

@end

При компиляции с Xcode 4.3.2 в режиме выпуска сборка (такая, что я могу ее понять) содержала вызовы objc_retain и objc_release в начале и в конце второго метода. Что происходит?

Это не является большой проблемой, но этот дополнительный трафик сохранения/освобождения появляется при использовании инструментов для профилирования чувствительного к производительности кода. Кажется, вы можете украсить аргументы метода с помощью __unsafe_unretained, чтобы избежать этого дополнительного сохранения/освобождения, как я уже делал в третьем примере, но делать это довольно неприятно.

4b9b3361

Ответ 1

См. этот ответ из списка рассылки на языке Objc:

Когда компилятор ничего не знает о управление памятью функции или метода (и это происходит лот), то компилятор должен предположить:

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

Учитывая # 1 и # 2; и учитывая, что ARC никогда не должна позволять объекту быть преждевременно освобожденный, то эти два предположения вынуждают компилятор чтобы сохранить переданные объекты чаще, чем нет.

Я думаю, что основная проблема заключается в том, что тело методов может привести к освобождению аргументов, чтобы ARC действовала защитно и сохраняла их:

- (void) processItems
{
    [self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
    [self doSomethingSillyWith:[items lastObject]];
}

- (void) doSomethingSillyWith: (id) foo
{
    [self setItems:nil];
    NSLog(@"%@", foo); // if ARC did not retain foo, you could be in trouble
}

Это также может быть причиной того, что вы не видите лишнее сохранение, когда theres просто один вызов в вашем методе.

Ответ 2

Передача в качестве параметра, в общем случае, не увеличивает количество удержаний. Однако, если вы передаете его на что-то вроде NSThread, оно специально задокументировано, что оно сохранит параметр для нового потока.

Итак, без примера того, как вы собираетесь начинать этот новый поток, я не могу дать окончательного ответа. В общем, все должно быть хорошо.

Ответ 3

Даже ответ души правильный, он немного глубже, чем он должен быть:

Сохраняется, потому что переданная ссылка назначается сильной переменной, переменной параметра. Это и только это причина пары сохранения/выпуска. (Задайте параметр var для __weak и что происходит?)

Можно ли его оптимизировать? Это походило бы на оптимизацию каждой пары сохранения/выпуска на локальных переменных, поскольку параметры являются локальными переменными. Это можно сделать, если компилятор понимает код дыры внутри метода, включая все отправленные сообщения и вызовы функций. Это может быть применено, что редко этот clang даже не пытается это сделать. (Представьте, что arg указывает на человека (только), принадлежащего к группе, и группа dealloc'd: человек также был бы dealloc'd.)

И да, не сохранять аргументы в MRC было своего рода опасным, но, как правило, разработчики хорошо знают свой код, что они оптимизировали сохранение/освобождение, не задумываясь об этом.

Ответ 4

Он не будет увеличиваться за кулисами. В ARC, если объект Strong, он просто останется в живых, пока нет более сильных указателей на него. Но это действительно не имеет никакого отношения к объекту, передаваемому как параметр, или нет.