Быстрое восстановление памяти строк (устройство с ограниченным объемом ОЗУ) - PullRequest
2 голосов
/ 30 ноября 2010

Я пишу приложение на C # для устройства с ограниченной оперативной памятью. (Моно на iPhone / iPad)

Когда я назначаю большую строку:

string xml = "10 meg xml string from REST service";

затем очистите его

xml = null;

С GC освободить эту память как можно скорее? Есть ли способ убедиться, что он убран. У GC есть функция сбора, но выполняется ли она сразу?

Проблема в том, что я загружаю много больших XML-файлов в цикле, и, хотя я устанавливаю строку в нуль, использование памяти растет.

Ответы [ 4 ]

4 голосов
/ 30 ноября 2010

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

Чтобы вызвать сбор, вам нужно две строки:

GC.Collect();
GC.WaitForPendingFinalizers();

РЕДАКТИРОВАТЬ: Написал это до того, как я увидел вашу заметку о том, на чем вы работали.Это написано на основе настольного компьютера .NET.Это может (или не может) быть другим на моно / iPad.

2 голосов
/ 19 ноября 2012

Я думаю, что если вы разрабатываете для iPhone, у вас нет сборщика gargabe из .net framework. Управление памятью осуществляется операционной системой, в данном случае iOS.

Я думаю, что вы должны проверить в моно документации, чтобы найти, как управлять памятью в этом случае. В XCode реализовано и автоматическое управление объектами, называемое автоматическим подсчетом ссылок, и это не сборщик мусора, как в .net framework, а просто автоматический инструмент для освобождения неиспользуемых объектов.

Теперь, думая только о .net при работе с большими строками, вы всегда должны использовать stringbuilder вместо просто string.

Теперь, думая, в iOS нельзя сравнивать приложение, написанное для среды iOs, с настольным приложением для Windows (на компьютере у вас гораздо больше ресурсов). IOS не допустит значительного снижения потребления памяти, если приложение сделает это, операционная система автоматически закроет его для поддержания работающей системы.

2 голосов
/ 30 ноября 2010

Во-первых, следует избегать одновременного хранения больших строк или больших массивов в памяти, особенно на устройствах с ограниченным объемом памяти, таких как телефоны. Используйте XmlTextReader, например, для разбора XML-файлов. Если вы получаете их из сети, сохраните их на диск и т. Д.

Далее проблема сбора мусора: текущий Mono GC выполняет консервативное сканирование стеков потоков, что означает, что некоторые указатели на объекты все еще могут быть видимы для GC, даже если для программиста они были очищены ( как установка на ноль в вашем примере). Чтобы ограничить последствия этого поведения, вы должны попытаться выделить или иным образом манипулировать большими массивами и строками в отдельном кадре стека. Например, вместо того, чтобы кодировать это так:

  while (true) {
    string s = get_big_string_from_network ();
    do_something_with_string(s);
    handle_ui ();
    s = null;
  }

сделать следующее:

  void manipulate_big_string() {
    string s = get_big_string_from_network ();
    do_something_with_string(s);
  }
  ...
  while (true) {
    manipulate_big_string ();
    handle_ui ();
  }

Обычно установка ссылки на ноль имеет желаемый эффект только при применении к статическому или экземпляру поля, его использование с локальной переменной метода может быть недостаточно для скрытия ссылки из ГХ.

1 голос
/ 30 ноября 2010

Хотя я не эксперт по Mono, но проверю некоторые простые вещи.Несмотря на то, что вы отметили, что устанавливаете для своей переменной значение null, действительно ли вы вызываете метод .Close () или .Dispose (), в зависимости от ситуации, или включаете область действия рассматриваемой переменной внутри блока using?

Возможно, это проблема, когда вы застреваете в ожидании финализатора (т. Е. Если у вас есть дескриптор на непомеченном ресурсе, таком как дескриптор файла), или переменная все еще застряла в области действияпричина.Это может привести к увеличению нагрузки на память.

В идеале, обрабатывать открытие файла по одному в методе с явно очищенной областью действия переменной в сочетании с блоком using, таким образом гарантируя, что соответствующие финализаторы и т. Д. Вызываютсядаже если выдается исключение.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...