Como faço para armazenar objetos em cache com eficiência em Java usando a RAM disponível?

StackOverflow https://stackoverflow.com/questions/2158868

Pergunta

Preciso armazenar objetos em cache em Java usando uma proporção de qualquer RAM disponível.Estou ciente de que outras pessoas fizeram essa pergunta, mas nenhuma das respostas atende aos meus requisitos.

Meus requisitos são:

  • Simples e leve
  • Não dramaticamente mais lento que um HashMap simples
  • Use LRU ou alguma política de exclusão que se aproxime do LRU

Eu tentei o LinkedHashMap, mas ele exige que você especifique um número máximo de elementos e não sei quantos elementos serão necessários para preencher a RAM disponível (seus tamanhos variam significativamente).

Minha abordagem atual é usar o MapMaker do Google Collection da seguinte maneira:

Map<String, Object> cache = new MapMaker().softKeys().makeMap();

Isso pareceu atraente, pois deveria excluir elementos automaticamente quando precisar de mais RAM, porém há um problema sério:seu comportamento é preencher toda a RAM disponível, momento em que o GC começa a se debater e o desempenho de todo o aplicativo se deteriora drasticamente.

Já ouvi falar de coisas como EHCache, mas parece bastante pesado para o que preciso e não tenho certeza se é rápido o suficiente para minha aplicação (lembrando que a solução não pode ser dramaticamente mais lenta que um HashMap) .

Foi útil?

Solução

Eu tenho requisitos semelhantes aos seus - simultaneidade (em 2 CPUs hexacore) e LRU ou similar - e também experimentei o Guava MapMaker.Achei softValues() muito mais lento do que fracoValues(), mas ambos tornaram meu aplicativo terrivelmente lento quando a memória ficou cheia.

Eu tentei o WeakHashMap e foi menos problemático, estranhamente ainda mais rápido do que usar o LinkedHashMap como um cache LRU por meio do método removeEldestEntry().

Mas o mais rápido para mim é ConcurrentLinkedHashMap o que tornou meu aplicativo 3-4 (!!) vezes mais rápido do que qualquer outro cache que experimentei.Alegria, depois de dias de frustração!Aparentemente, ele foi incorporado ao MapMaker do Guava, mas o recurso LRU não está no Guava r07 de qualquer forma.Espero que funcione para você.

Outras dicas

Eu implementei caches serval e provavelmente é tão difícil quanto implementar uma nova fonte de dados ou threadpool, minha recomendação é usar jboss-cache ou outro lib de cache bem conhecido. Então você vai dormir bem sem problemas

Ouvi falar de coisas como Ehcache, mas parece bastante pesado para o que preciso, e não tenho certeza se é rápido o suficiente para minha aplicação (lembrando que a solução não pode ser dramaticamente mais lenta que um hashmap) .

Eu realmente não sei se alguém pode dizer isso Ehcache é pesado. Pelo menos, não considero o ehcache como tal, especialmente ao usar um Loja de memória (que é apoiado por um estendido LinkedHashMap e é claro que a opção de cache mais rápida). Você deve tentar.

Eu acredito MapMaker Será a única maneira razoável de conseguir o que você está pedindo. Se "o GC começar a bater e o desempenho do aplicativo inteiro se deteriora drasticamente", você deve gastar algum tempo definindo corretamente os vários parâmetros de ajuste. Este documento pode parecer um pouco intimidador a princípio, mas na verdade está escrito com muita clareza e é uma mina dourada de informações úteis sobre o GC:

http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf

Não sei se essa seria uma solução simples, especialmente em comparação com o ehcache ou similar, mas você já olhou para o Biblioteca Javolution? Não foi projetado para como tal, mas no javolution.context Pacote Eles têm um padrão de alocador que pode reutilizar objetos sem a necessidade de coleta de lixo. Dessa forma, eles mantêm a criação de objetos e a coleta de lixo ao mínimo, um recurso importante para a programação em tempo real. Talvez você deva dar uma olhada e tentar adaptá -lo ao seu problema.

Isso parecia atraente, pois deveria excluir automaticamente elementos quando precisar de mais RAM, no entanto, há um problema sério: seu comportamento é preencher toda a RAM disponível

O uso de teclas SOFT apenas permite que o coletor de lixo remova os objetos do cache quando nenhum outro objetivo faz referência a eles (ou seja, quando a única coisa que se refere à tecla de cache é o próprio cache). Não garante nenhum outro tipo de expulsão.

A maioria das soluções encontradas será adicionada à parte superior das classes de mapa Java, incluindo o Ehcache.

Você já olhou para o Collecções comuns Lrumap?

Observe que existe um emissão aberta contra o Mapmaker para fornecer funcionalidade LRU/MRU. Talvez você possa expressar sua opinião lá também

Usando o seu cache existente, armazene a referência fraca em vez de referências de objetos normais.

Se o GC começar a ficar sem espaço livre, os valores mantidos por fracos serão lançados.

No passado eu usei JCS. Você pode configurar o configuração Para tentar atender às suas necessidades. Não tenho certeza se isso atenderá a todos os seus requisitos/necessidades, mas achei que era bastante poderoso quando o usei.

Você não pode "excluir elementos" que você só pode parar para referenciar -os e aguarde o GC limpá -los, então continue com o Google Collections ...

Não estou ciente de uma maneira fácil de descobrir o tamanho de um objeto em Java. Portanto, acho que você não encontrará uma maneira de limitar uma estrutura de dados pela quantidade de RAM que está tomando.

Com base nessa suposição, você está preso a limitá -lo pelo número de objetos em cache. Sugiro que a execução de simulações de alguns cenários de uso da vida real e coleta de estatísticas sobre os tipos de objetos que entram no cache. Em seguida, você pode calcular o tamanho estatisticamente médio e o número de objetos que pode se dar ao luxo de armazenar em cache. Embora seja apenas uma aproximação da quantidade de RAM que você deseja dedicar ao cache, pode ser bom o suficiente.

Quanto à implementação do cache, no meu projeto (um aplicativo crítico de desempenho) estamos usando o ehcache e, pessoalmente, não acho que seja um peso pesado.

De qualquer forma, execute vários testes com várias configurações diferentes (em relação ao tamanho, política de despejo etc.) e descubra o que funciona melhor para você.

Cache de algo, SoftReference Talvez a melhor maneira até agora eu possa imaginar.

Ou você pode reinventar um pool de objeto. Que todo objeto que você não usa, não precisa destruí -lo. Mas para salvar a CPU em vez de salvar memória

Supondo que você queira que o cache seja seguro, você deve examinar o exemplo do cache no livro de Brian Goetz, "Java Concurrency in Practice". Não posso recomendar isso o suficiente.

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