Ответ 1
РЕДАКТИРОВАТЬ: В ответе ниже я упомянул о том, что внутренний пул является специфичным для AppDomain; Я почти уверен, что то, что я наблюдал раньше, но документы MSDN для String.Intern предполагают, что существует один общий пул для всего процесс, делая это еще более важным.
Оригинальный ответ
(я собирался добавить это как комментарий, но я думаю, что это достаточно важный момент для получения дополнительного ответа...)
Как объяснили другие, интернирование строк выполняется для всех строковых литералов, но не для "динамически созданных" строк (например, те, которые читаются из базы данных или файла или построены с использованием StringBuilder
или String.Format
.)
Однако я бы не предложил называть String.Intern
, чтобы обойти последний пункт: он будет заполнять интервал для жизни вашего AppDomain
. Вместо этого используйте пул, который является локальным только для вашего использования. Вот пример такого пула:
public class StringPool
{
private readonly Dictionary<string,string> contents =
new Dictionary<string,string>();
public string Add(string item)
{
string ret;
if (!contents.TryGetValue(item, out ret))
{
contents[item] = item;
ret = item;
}
return ret;
}
}
Тогда вы просто используете что-то вроде:
string data = pool.Add(ReadItemFromDatabase());
(Обратите внимание, что пул не является потокобезопасным, нормальное использование ему не понадобится.)
Таким образом вы можете выбросить свой пул, как только он вам больше не понадобится, вместо того, чтобы навсегда сохранить потенциально большое количество строк. Вы также могли бы сделать это умнее, внедрить кеш LRU или что-то еще, если вы действительно захотите.
EDIT: просто для того, чтобы уточнить, почему это лучше, чем использовать String.Intern
... предположим, что вы читаете кучу строк из базы данных или файла журнала, обрабатываете их, а затем переходите на другую задачу. Если вы вызываете String.Intern
в этих строках, они никогда не будут собираться мусором, пока ваш AppDomain
жив, и, возможно, даже не тогда. Если вы загружаете несколько разных файлов журналов, вы постепенно накапливаете строки в своем пуле, пока не закончите или не закончите работу. Вместо этого я предлагаю такой шаблон:
void ProcessLogFile(string file)
{
StringPool pool = new StringPool();
// Process the log file using strings in the pool
} // The pool can now be garbage collected
Здесь вы получаете преимущество нескольких строк в том же файле, что только один раз в памяти (или, по крайней мере, только один раз пропустил gen0 один раз), но вы не загрязняете "глобальный" ресурс (пул пула).