Comportamento de garbage collection para String.intern ()

Se eu usar String.intern () para melhorar o desempenho, como posso usar “==” para comparar uma string internada, vou me deparar com problemas de garbage collection? Como o mecanismo de garbage collection de strings interned difere das strings normais?

Na verdade, isso não é uma otimização de garbage collection, mas sim uma otimização de pool de strings. Quando você chama String.intern() , substitui a referência à sua String inicial pela referência base (a referência da primeira vez que essa string foi encontrada ou essa referência, se ainda não for conhecida).

No entanto, ele se tornará um problema do coletor de lixo, uma vez que sua cadeia de caracteres não terá mais uso no aplicativo, já que o conjunto de cadeias de caracteres interno é um membro estático da class String e nunca será coletado como lixo.

Como regra geral, considero preferível nunca usar este método interno e deixar o compilador usá-lo apenas para constantes Strings, aquelas declaradas assim:

 String myString = "a constant that will be interned"; 

Isso é melhor, no sentido de não permitir que você faça a suposição falsa == poderia funcionar quando não.

Além disso, o fato é que String.equals chama subjacentemente == como uma otimização, garantindo que a otimização de strings internamente seja usada sob o capô. Esta é mais uma evidência == nunca deve ser usada em Strings.

String.intern() gerencia um pool interno, implementado de forma nativa, que possui alguns resources especiais relacionados ao GC. Este é o código antigo, mas se fosse implementado de novo, usaria um java.util.WeakHashMap . Referências fracas são uma maneira de manter um ponteiro para um object sem impedi-lo de ser coletado. Apenas a coisa certa para um pool unificador, como seqüências de caracteres internas.

As sequências internas que são coletadas como lixo podem ser demonstradas com o seguinte código Java:

 public class InternedStringsAreCollected { public static void main(String[] args) { for (int i = 0; i < 30; i ++) { foo(); System.gc(); } } private static void foo() { char[] tc = new char[10]; for (int i = 0; i < tc.length; i ++) tc[i] = (char)(i * 136757); String s = new String(tc).intern(); System.out.println(System.identityHashCode(s)); } } 

Este código cria 30 vezes a mesma string, internando-a a cada vez. Além disso, ele usa System.identityHashCode() para mostrar o código de hash que Object.hashCode() teria retornado nessa cadeia de caracteres interned. Quando executado, esse código imprime valores inteiros distintos, o que significa que você não obtém a mesma instância a cada vez.

De qualquer forma, o uso de String.intern() é um pouco desencorajado. É um pool estático compartilhado, o que significa que ele se transforma facilmente em um gargalo em sistemas com vários núcleos. Use String.equals() para comparar strings, e você viverá mais e mais feliz.

Este artigo fornece a resposta completa.

No java 6, o conjunto de cadeias de caracteres reside no PermGen, desde o java 7, o conjunto de cadeias de caracteres reside na memory da pilha.

Seqüências manualmente internadas serão coletadas como lixo.
Os literais de string serão apenas coletados como lixo se a class que os define for descarregada.

O conjunto de strings é um HashMap com tamanho fixo que era pequeno no java 6 e versões anteriores do java 7, mas aumentou para 60013 desde o java 7u40.
Ele pode ser alterado com -XX: StringTableSize = e exibido com as opções java -XX: + PrintFlagsFinal .

Por favor, leia: http://satukubik.com/2009/01/06/java-tips-memory-optimization-for-string/

A conclusão que posso obter de sua informação é: Você internou muitos String . Se você realmente precisar estagiar tantos String para otimização de desempenho, aumente a memory do perm gen , mas se eu fosse você, eu verificaria primeiro se eu realmente precisava de tantas String internadas.