Pergunta

Estou prejudicando o Java com um hash grande (milhões) que é realmente construído com uma capacidade de 10.000 e um fator de carga de 0,75 e é usado para cache alguns valores

Como os valores em cache se tornam inúteis com o tempo (não mais acessados), mas não posso remover os inúteis enquanto gostaria de esvaziar completamente o cache quando seu desempenho começar a se degradar. Como posso decidir quando é bom fazer isso?

Por exemplo, com 10 milhões de capacidade e 0,75, devo esvaziá -lo quando atingir 7,5 milhões de elementos? Porque eu tentei vários valores limite, mas gostaria de ter um analítico.

Eu já testei o fato de que emagrecer quando está cheio é um impulso para o Perfomance (primeiro 2-3 iterações de algoritmo depois que o limpe

Editar: informações adicionais

O hashmap tem as chaves e flutuam como valores. Ele contém correlação em cache de conteúdo, pois é um produto de pontos de vetores de tags, eu queria cache -os (aumentar o desempenho).

Então, basicamente, o que eu faço é calcular um long chave usando os códigos de hash dos 2 conteúdos:

static private long computeKey(Object o1, Object o2)
{
    int h1 = o1.hashCode();
    int h2 = o2.hashCode();

    if (h1 < h2)
    {
        int swap = h1;
        h1 = h2;
        h2 = swap;
    }

    return ((long)h1) << 32 | h2;
}

e use -o para recuperar valores armazenados. O que acontece é que, uma vez que é um conteúdo hierárquico de cluster, e seus valores de correlação com outros conteúdos não são mais necessários. É por isso que quero limpar o hashmap de tempos em tempos, para evitar a degradação devido a valores inúteis dentro dele.

Usando um WeakHashMap Vai acabar com os dados imprevisivelmente quando ainda forem necessários. Não tenho controle sobre eles.

Obrigado

Foi útil?

Solução

Por que não usar um cache LRU? Da documentação do Java LinkedHashmap:

Um construtor especial é fornecido para criar um mapa de hash vinculado cuja ordem de iteração é a ordem em que suas entradas foram acessadas pela última vez, a partir de mais recentemente acessadas a mais recentemente (ordem de acesso). Esse tipo de mapa é adequado para a construção de caches LRU. Invocar o método PUT ou GET resulta em acesso à entrada correspondente (supondo que ela exista após a conclusão da invocação). O método Putall gera um acesso de entrada para cada mapeamento no mapa especificado, na ordem em que os mapeamentos de valor-chave são fornecidos pelo iterador de conjunto de entrada do mapa especificado. Nenhum outro método gera acessos de entrada. Em particular, as operações em visualizações de coleta não afetam a ordem de iteração do mapa de apoio.

Então, basicamente, de vez em quando, à medida que seu mapa fica muito grande, basta excluir os primeiros valores X que o iterador fornece.

Veja documentação para removeEldestEntry para fazer isso para você automaticamente.

Aqui está o código que demonstra:

 public static void main(String[] args) {
    class CacheMap extends LinkedHashMap{
      private int maxCapacity;
      public CacheMap(int initialCapacity, int maxCapacity) {
        super(initialCapacity, 0.75f, true);
        this.maxCapacity = maxCapacity;
      }

      @Override
      protected boolean removeEldestEntry(Map.Entry eldest) {
        return size()>maxCapacity;
      }
    }

    int[] popular = {1,2,3,4,5};
    CacheMap myCache = new CacheMap(5, 10);
    for (int i=0; i<100; i++){
      myCache.put(i,i);
      for (int p : popular) {
        myCache.get(p);
      }
    }

    System.out.println(myCache.toString()); 
    //{95=95, 96=96, 97=97, 98=98, 99=99, 1=1, 2=2, 3=3, 4=4, 5=5}
  }

Outras dicas

Você investigou Fracoshashmaps ? O coletor de lixo pode determinar quando remover as coisas e pode fornecer um substituto aceitável em vez de codificar algo sozinho.

Este artigo tem informações mais úteis.

Você pode querer usar o Google Collections ' Cartógrafo Para fazer um mapa com referências suaves e um tempo limite específico.

Referências suaves "são liberadas a critério do coletor de lixo em resposta à demanda da memória".

Exemplo:

ConcurrentMap<Long, ValueTypeHere> cacheMap = new MapMaker()
    .concurrencyLevel(32)
    .softValues()
    .expiration(30, TimeUnit.MINUTES)
    .makeMap();

Você também pode especificar Keys fracos se quiser fazer suas chaves agirem como as de um hashmap fraco.

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