Pull to refresh

Comments 9

Иногда бывает полезно реализовывать собственную тематическую таблицу для интернирования строк и юзать какой-нибудь ConcurrentDictionary или массив. Или thread-local.
Например, для хранения строкового представления байтов в проге, если надо выводить много раз строковое представление байтов.
Было бы очень любопытно узнать, какой же прирост в производительности дало вам интернирование.
На первый взгляд выглядит так, что вы героически решаете проблемы, которые сами же создали :).
Изначально, как я понимаю, интернирование было использовано, чтобы просто уменьшить расход памяти, без цели увеличения производительности, скорее всего его там и не было. Ради интереса я убирал интернирование и видел, как процесс увеличивался почти в два раза — с 6 ГБ до 12 ГБ.

На первый взгляд выглядит так, что вы героически решаете проблемы, которые сами же создали :).

Частично так и есть — уменьшили расход памяти процессом, но создали несовсем очевидную проблему производительности в сценариях работы в системах с большим колличеством потоков (по типу использования IncrediBuild для расспараллеливания).

Не совсем по теме. но: недавно велосипедил интернирование через concurrentdictionary. В двух словах — обработка здоровых корпусов текстов (токенизация и т.п), надо было вести статистику по отдельным словам.


В общем, это замедлило чтение раз в 5 (не всю программу, просто чтение), дав при этом экономию памяти раза в 4.


Стоит ли игра свеч? Универсальных ответов, как водится, не бывает.

Нет, альтернативные подходы не пробовали. Про StringPool, честно говоря, вообще не слышал до этого. Нужно будет попробовать, хотя тоже сомневаюсь, что внутри него нет блокировок.
К слову, стрингпул можно свой взять, не используя шаренный.
Раз пошла тема про интернирование, вытащу вопрос со SO, который появился у меня недавно. Я баловался со строками и заметил разницу в поведении памяти при интернировании. Если коротко, то генерировал много строк из ограниченного набора символов. В net.core 3.1 размер кучи почему-то не уменьшался после сборки мусора, если количество строк (размер в памяти?) была больше определенного значения.

Код
class Program
{
    public static void Main(string[] args)
    {
        long memory = GC.GetGCMemoryInfo().HeapSizeBytes;
        Console.WriteLine(memory);

        Get10MillionStringsInterned();

        memory = GC.GetGCMemoryInfo().HeapSizeBytes;
        Console.WriteLine(memory);

        GC.Collect();

        memory = GC.GetGCMemoryInfo().HeapSizeBytes;
        Console.WriteLine(memory);

        memory = GC.GetTotalMemory(true);
        Console.WriteLine(memory);

        Console.ReadKey();
    }

    static void Get10MillionStringsInterned()
    {
        var chars = new char[] { 'a', 'b', 'c',  };
        char[] word = new char[4];
        Random r = new Random();
        string[] strings = new string[10_000_000];

        for (int i = 0; i < strings.Length; i++)
        {
            for (int j = 0; j < word.Length; j++)
            {
                word[j] = chars[r.Next(chars.Length)];
            }

            strings[i] = string.Intern(new string(word));
        }
        Console.WriteLine(strings[r.Next(strings.Length)]);
    }
}


Вывод консоли
0
aabb 
80082696 
77312    <-- Heap size
76480

Разница, если малость прибавить символов в массив chars:
0
badb
80092448
80086896 <-- Heap size
86200


А .net Framework и 5.0 работали как я предполагал.
Sign up to leave a comment.