2013-09-05 3 views
2

У меня проблемы с памятью с моим приложением iOS, и у меня есть несколько вопросов об этом.Вопросы о предупреждениях памяти

Ели из всех, я работаю с iOS 6, и я использую ARC.

Теперь позвольте мне объяснить мою ситуацию:

У меня есть 2 точки зрения. С первого взгляда, если я нажимаю на кнопку, я создаю вторую точку зрения (с помощью alloc и init) и отобразить его как модальный используя этот код:

[self presentViewController:secondView animated:YES completion:^{ 
     [secondView prepareToDraw]; // Function I use to start my computations and rendering 
}]; 

В какой-то момент, когда расчеты закончены I хотите закрыть второе представление и вернуться к первому виду. Я использую этот код из моего второй точки зрения:

[self dismissViewControllerAnimated:YES completion:^{ 
      [self finished]; // Function I use to free some malloc 
}]; 

Я бег моего приложения с инструментами распределением и утечками и у меня нет никаких утечек.

Вот код моего didReceiveMemoryWarning:

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 

    if ([self isViewLoaded] && ([[self view] window] == nil)) { 
     self.view = nil; 

     [self tearDownGL]; 

     if ([EAGLContext currentContext] == self.context) { 
      [EAGLContext setCurrentContext:nil]; 
     } 
     self.context = nil; 
    } 

    // Dispose of any resources that can be recreated. 
    NSLog(@"Resources freed"); 
} 

tearDownGL функция освобождает OpenGLES ресурсы, такие как текстуры, вершинные массивы, ...

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

Вот мои вопросы:

1- ли приложение автоматически освобождая мою UIImage, UIView, ... из моих контроллеров? Если нет, как я могу освободить их, поскольку я использую ARC? Я также видел функцию viewDidUnload, но это не рекомендуется, как сказано в документации:

Вызывается, когда вид контроллера освобождается из памяти. (Не Устаревшие в прошивкой 6.0. Представления уже не продувают в условиях низкой памяти и поэтому этот метод никогда не вызывается.)

Но если взгляды не продували больше в условиях низкой памяти, как я могу бесплатно больше памяти, чтобы предотвратить сбой приложения? Что мне делать?

2- Я поставил точку останова на функцию didReceiveMemoryWarning для моих 2 контроллеров. Когда я запускаю приложение на симуляторе, я имитирую предупреждение о памяти. Я вижу, что didReceiveMemoryWarning вызывается один раз для моих 2 контроллеров. Но если я переключаюсь несколько раз между моим первым и вторым контроллерами, то didReceiveMemoryWarning вызывается один раз для моего первого контроллера вида, но вызывается несколько раз для моего второго контроллера представления. Если я переключусь 3 раза, функция будет называться 3 раза. Поэтому, я думаю, когда я «закрываю» свое второе представление, чтобы вернуться к первому представлению, второе представление не освобождается и все еще существует. Зачем ? Как я могу заставить его быть уничтоженным? (поскольку я больше не буду его использовать и создаю новый) Я создаю второй контроллер представления в функции, и я не могу ссылаться на него (он не сохраняется в классе).

ответ

1

Вы должны освободить (в ARC, что означает установку всех сильных ссылок на нуль) всю память (изображения, объекты NSData, массивы, все данные, представленные уровнем модели и т. Д.), Которые в настоящее время не требуются и могут (easiyl) быть повторно созданные, когда они снова используются. Весь ваш другой код должен быть написан таким образом, чтобы свойства/iVars проверялись на отсутствие, если эти объекты могли быть выпущены во время предупреждения о памяти, а затем будут воссозданы.

Я сомневаюсь, что self.view является одним из объектов, которые могут быть утилизации.

Возможно, вы представили UIImageView. Это было создано с помощью объекта UIImage. Вы не нуждаетесь в этом UIImage в памяти, пока отображается UIImageView. (Если UIImageView по-прежнему нуждается в этом, он сохраняет его или сохраняет сильную ссылку на его onw, так что вам не нужно беспокоиться о сохранении самого изображения.) ЭТО ресурсы, которые будут выпущены.

Если self.context является одним из ресурсов утилизации, я не могу сказать. Это вполне может быть.

+0

Настройка переменных на nil работает для меня. Но это странно, почему не переменная, освобожденная в конце блока напрямую? –

+0

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

+0

Спасибо, я понимаю, как это работает сейчас –

1

ARC не всегда означает, что изображения, представления и т. Д. Будут выпущены мгновенно. Он добавляется в ближайший дуговой пул и освобождается. Если приложение может потребовать его или использует его где-то, оно добавляется в основной пул, который освобождается только тогда, когда приложение завершается. Поэтому лучше удалить объект самостоятельно, если вы считаете, что это послужило ему цели. Особенно в случае изображений он остается в памяти, так как он не знает, используется ли он где-то еще или нет.

1

Всякий раз, когда вы работаете с блоками, вы должны использовать слабую ссылку на себя, поскольку это может привести к удержанию циклов. Поэтому измените свой код на это:

__weak typeof(self) blockSelf = self; 
[self dismissViewControllerAnimated:YES completion:^{ 
    [blockSelf finished]; // Function I use to free some malloc 
}]; 

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

Ваш первый вызов также кажется неправильным:

[self presentViewController:secondView animated:YES completion:^{ 
     [secondView prepareToDraw]; // Function I use to start my computations and rendering 
}]; 

Если prepareToDraw происходит только один раз, когда контроллер представлен в первый раз, чем вы должны запустить этот код в viewDidLoad. Это также принесет пользу вашей архитектуре, поскольку только сам контроллер должен знать, что ему нужно настроить в начале и отменить в конце.

Надеюсь, что это поможет. Возможно, в вашем коде есть другие проблемы.

+0

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

1

Пожалуйста, посмотрите на авто-разблокировки, бассейнов: AutoReleasePools

Читаем:

Использование Местные Autorelease бассейн Блоки для снижения пиковых памяти Footprint

Многие программы создают временные объекты, которые autoreleased , Эти объекты добавляют к области памяти программы до конца блока. Во многих ситуациях, позволяя временным объектам накапливаться до конца текущей итерации цикла событий, не приводит к чрезмерным накладным расходам; в некоторых ситуациях, однако, вы можете создать большое количество временных объектов, которые существенно увеличивают объем памяти и что вы хотите избавиться быстрее. В этих последних случаях вы можете создать свой собственный блок пула авторезистов.В конце блока, временные объекты освобождаются, что обычно приводит к их открепления, тем самым уменьшая объем памяти программы

У меня была аналогичная проблема, где я инкапсулированный все большие OBJETS, что я хотел, чтобы избавиться от в блоке @autoreleasepool.

+0

autoreleasepool, похоже, работает. Ваш ответ также решил мою проблему. Однако Герман Клеккер был первым, поэтому принял его ответ –

Смежные вопросы