Строки и сбор мусора

Я слышал противоречивые истории по этой теме, и я ищу немного ясности.

Как удалить объект string сразу или, по крайней мере, очистить его?

Ответы

Ответ 1

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

Подробнее о интернинге здесь в этом вопросе: Где строковые литералы Java и .NET?

Ответ 3

Я отвечу на этот вопрос с точки зрения безопасности.

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

Проблема заключается в том, что после создания System.String в управляемом приложении на самом деле вы не можете много сделать. Может быть какой-то скрытый способ сделать небезопасное отражение и переписать байты, но я не могу себе представить, чтобы такие вещи были надежными.

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

У меня была эта проблема один раз с системой, которую я разработал для некоторых ноутбуков компании. Жесткие диски не были зашифрованы, и я знал, что если кто-то возьмет ноутбук, они смогут легко отсканировать его для получения конфиденциальной информации. Я хотел защитить пароль от таких атак.

То, как я это делаю, заключается в следующем: я помещаю пароль в массив байтов, захватывая события нажатия клавиш в элементе управления текстовым полем. В текстовом поле никогда не было ничего, кроме звездочек и отдельных символов. Пароль никогда не существовал как строка в любое время. Затем я хэшировал массив байтов и обнулял оригинал. Хэш был затем XORed со случайным жестко запрограммированным ключом, и это было использовано для шифрования всех конфиденциальных данных.

После того, как все было зашифровано, ключ был обнулен.

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

Ответ 4

Я написал небольшой метод расширения для строкового класса для таких ситуаций, вероятно, единственный верный способ обеспечить, чтобы сама строка была нечитаемой до тех пор, пока она не будет собрана. Очевидно, что работает только с динамически генерируемыми строками, а не с литералами.

public unsafe static void Clear(this string s)
{
  fixed(char* ptr = s)
  {
    for(int i = 0; i < s.Length; i++)
    {
      ptr[i] = '\0';
    }
  }
}

Ответ 5

Это все до сборщика мусора, чтобы справиться с этим для вас. Вы можете заставить его запустить очистку, вызвав GC.Collect(). Из документов:

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

Все объекты, независимо от того, как долго они были в памяти, являются считается для сбора; Однако, объекты, на которые ссылаются управляемые код не собираются. Использовать это метод, чтобы заставить систему попытаться вернуть максимальную сумму доступной памяти.

Что самое близкое, что вы заставите меня думать!

Ответ 6

Нет никакого детерминированного способа удалить все следы строки (System.String) из памяти. Ваши единственные опции - использовать массив символов или a SecureString.

Ответ 7

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

Это распространенная ошибка для младших разработчиков объявить свои строки private string ... 'в самом классе.

Я также видел опытных разработчиков, пытающихся кэшировать сложную конкатенацию строк (a + b + c + d...) в частной переменной-члене, поэтому им не нужно ее вычислять. Большая ошибка - для ее пересчета не требуется много времени, временные строки собирают мусор почти сразу же, когда происходит первое поколение GC, и память, проглоченная путем кэширования всех этих строк, просто достала доступную память от более важных элементов, таких как кэшированные записи базы данных или кэшированный вывод страницы.

Ответ 8

Установите строковую переменную в значение null, когда она вам не понадобится.

string s = "dispose me!";
...
...
s = null;

а затем вызовите GC.Collect(), чтобы отменить сборщик мусора, но GC НЕ МОЖЕТ гарантировать, что строка будет собрана немедленно.