Pergunta

Se eu tiver um HashMap parecido com este:

HashMap<String, MyObject>

onde o String key é um campo em MyObject, esse valor de string é armazenado duas vezes?

Então, quando adiciono entradas:

_myMap.put(myObj.getName(), myObj);

Estou usando o dobro do tamanho da String em termos de memória?Ou o Java faz algo inteligente nos bastidores?

Obrigado

Foi útil?

Solução

O Java usa a referência, por isso é apenas um ponteiro para a string que armazena duas vezes. Portanto, você não precisa se preocupar se sua corda for enorme, ela ainda será a mesma quantidade de memória usada.

Outras dicas

A menos que você esteja realmente criando um novo valor String em getName(), você não está duplicando o uso de memória.

Aqui estão alguns exemplos para esclarecer as coisas:

 String s1 = "Some really long string!";
 String s2 = s1;
 assert s1.equals(s2);

Aqui, s1 == s2;eles se referem ao mesmo String instância.Seu uso de memória é de 2 variáveis ​​de referência (não é grande coisa), 1 String exemplo, e 1 apoio char[] (a parte que ocupa memória).


 String s1 = "Some really long string!";
 String s2 = new String(s1);
 assert s1.equals(s2);

Aqui, s1 != s2;eles se referem a diferentes String instâncias.Entretanto, como as strings são imutáveis, o construtor sabe que elas podem compartilhar o mesmo array de caracteres.Seu uso de memória é de 2 variáveis ​​de referência, 2 String instâncias (ainda não é grande coisa, porque...), e 1 apoio char[].


 String s1 = "Some really long string!";
 String s2 = new String(s1.toCharArray());
 assert s1.equals(s2);

Aqui, como antes, s1 != s2.Um construtor diferente é usado, desta vez, porém, que leva um tempo char[] em vez de.Para garantir a imutabilidade, toCharArray() deve devolver uma cópia defensiva de sua matriz interna (dessa forma, quaisquer alterações na matriz retornada não alterariam o valor da String).

[toCharArray() retorna] uma matriz de caracteres recém-alocada cujo comprimento é o comprimento desta string e cujo conteúdo é inicializado para conter a sequência de caracteres representada por esta string.

Para piorar a situação, o construtor também deve copiar defensivamente o array fornecido ao seu array de apoio interno, novamente para garantir a imutabilidade.Isso significa que até 3 cópias da matriz de caracteres pode residir na memória ao mesmo tempo!1 delas será coletada como lixo eventualmente, então seu uso de memória é de 2 variáveis ​​de referência, 2 String instâncias, e 2 apoio char[]! AGORA seu uso de memória é duplicado!


Então, voltando à sua pergunta, contanto que você não esteja criando um novo valor String em getName() (ou seja,se você simplesmente return this.name;), então você está bem.Porém, se você estiver fazendo uma concatenação simples (por exemplo, return this.firstName + this.lastName;), então você dobrará o uso de memória!

O código a seguir ilustra meu ponto:

public class StringTest {
    final String name;
    StringTest(String name) {
        this.name = name;
    }
    String getName() {
        return this.name;      // this one is fine!
    //  return this.name + ""; // this one causes OutOfMemoryError!
    }
    public static void main(String args[]) {
        int N = 10000000;
        String longString = new String(new char[N]);
        StringTest test = new StringTest(longString);
        String[] arr = new String[N];
        for (int i = 0; i < N; i++) {
            arr[i] = test.getName();
        }
    }
}

Você deve primeiro verificar se o código acima é executado (java -Xmx128m StringTest) sem lançar nenhuma exceção.Então, modifique getName() para return this.name + ""; e execute-o novamente.Desta vez você receberá um OutOfMemoryError.

String são imutáveis, mas ainda se aplicam a referência. Portanto, não será preciso duas vezes mais memória.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top