Сборка мусора зависит от различных факторов, таких как то, какой сборщик вы используете, физическую память машины, а также версию JVM, которую вы используете.Поскольку о них здесь не так много говорится, предсказать, что может быть причиной этого, довольно сложно.Я предполагаю, что вы используете Java 8, так как в настоящее время это более популярная версия.
Начиная с Java 8, в модели памяти JVM произошли изменения.Что, теперь нет места Permanent Generation
.Это место, где расположен String Pool
(я использую String
, следовательно, вы используете конкатенацию String
в циклах).См. Этот документ Модель памяти Java (JVM) - Управление памятью в Java .* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}}} * * * * * * * * * * * * * С тех пор, как в Java 8 появилась новая ячейка памяти с именем Metaspace
, которая находится в основной памяти за пределами основной памяти за пределами основной памяти *1013*JVM.
Кроме того, когда вы объединяете String
объекты, подобные этому, он не изменит существующий объект, поскольку String
является неизменным типом.Вместо этого он создает новые String
объекты с новым значением и помещает их в Metaspace
.Это может быть причиной того, что вы видите увеличение использования памяти.
Даже если Metaspace
находится внутри основной памяти / физической памяти и может динамически расширяться, все же имеет ограничение физической памяти.Вот почему я ранее говорил о физической памяти компьютера как о факторе зависимости.
Когда мы приступаем к сборке мусора, вы не упомянули никакой конфигурации GC.Поэтому я предполагаю, что вы используете Parallel GC , который является сборщиком Java 8 по умолчанию (вы можете узнать больше о GC по той же ссылке, что и выше).Я полагаю, что производительность Parallel GC
достаточна для этой задачи.Поэтому достаточно вызвать System.gc()
без какого-либо флага JVM.
Но, как вы упомянули, System.gc()
не очищает память, может произойти, поэтому вы используете отдельный поток для объединения этих строк.
Обычно строки, созданные с использованием строкового литерала (String s = "abc"
), не становятся приемлемыми для мусора.Это потому, что в коде каждого метода, использующего литерал, есть неявная ссылка на объект String
(проверьте этот ответ Когда строка будет собирать мусор в java ).Таким образом, вы должны потерять эти неявные ссылки, прекратив выполнение функции.
Поскольку вы используете новый Thread
для выполнения этой конкатенации, и я не могу найти место, где вы прерываете потоки вы вызываете Thread.yield()
( Thread.yield ), чтобы сообщить планировщику потока о необходимости использования ЦП для этого конкретного потока и пометить, что поток желает быть запланированным как можно скорее снова, проясните, что этот Thread
объект все еще живет и ссылается на эти объекты String, не делая их пригодными для мусора.Это может быть причиной того, что вызов System.gc()
не работает.
В качестве решения попробуйте interrupt
поток вместо yield
.
Обновление 1:
До Java 7 String Pool
находился в PermGen
, что не подходит для сборки мусора.PermGen
имеет фиксированный размер и не способен расширяться во время выполнения.Если у PermGen
недостаточно места, выдается ошибка java.lang.OutOfMemoryError: PermGen
.В качестве временного исправления мы можем увеличить размер PermGen
, используя флаг -XX:MaxPermSize=512m
.
Но помните, что это работает только на JVM до Java 8 и в Java 7, это не делает различий в смысле увеличения доступности String Pool
размера, следовательно, Java 7 и более, String Pool
перешел наHeap
пробел.