Diferença entre "on-heap" e "off-heap"


Respostas:


169

O armazenamento on-heap refere-se a objetos que estarão presentes no heap Java (e também estão sujeitos ao GC). Por outro lado, o armazenamento fora do heap refere-se a objetos (serializados) gerenciados pelo EHCache, mas armazenados fora do heap (e também não sujeitos ao GC). Como o armazenamento off-heap continua a ser gerenciado na memória, é um pouco mais lento que o armazenamento on-heap, mas ainda mais rápido que o armazenamento em disco.

Os detalhes internos envolvidos no gerenciamento e no uso da loja off-heap não são muito evidentes no link postado na pergunta; portanto, seria aconselhável verificar os detalhes do Terracotta BigMemory , que é usado para gerenciar o disco loja. O BigMemory (o repositório off-heap) deve ser usado para evitar a sobrecarga do GC em um heap de vários Megabytes ou Gigabytes. O BigMemory usa o espaço de endereço de memória do processo da JVM, por meio de ByteBuffers diretos que não estão sujeitos ao GC, diferentemente de outros objetos Java nativos.


18
+ 1 por mencionar ByteBuffers diretos para exploração adicional;)
Max

3
Os Direct ByteBuffers oferecem acesso à memória não gerenciada, mas estão sujeitos ao GC (em oposição aos dados para os quais apontam). Isso é importante porque um ByteBuffer direto (o tipo ByteBuffer.allocateDirect, não o tipo MMap) será coletado pelo GC e, quando coletado, o Deallocater será acionado, coletando efetivamente a memória não gerenciada.
Nitsan Wakart

O uso de Inseguro para alocar objetos parece ter um desempenho significativamente melhor de leitura e gravação em Onheap / DirectByteBuffers / ByteBuffers. ashkrit.blogspot.com/2013/07/...
Joe C

98

em http://code.google.com/p/fast-serialization/wiki/QuickStartHeapOff

O que é Heap-Offloading?

Normalmente, todos os objetos não temporários que você aloca são gerenciados pelo coletor de lixo do java. Embora a VM faça um trabalho decente na coleta de lixo, em um determinado momento, a VM precisa fazer o chamado 'GC completo'. Um GC completo envolve a varredura do Heap alocado completo, o que significa que as pausas / desacelerações do GC são proporcionais ao tamanho do heap de aplicativos. Portanto, não confie em ninguém que diga "A memória é barata". Na memória java, o consumo prejudica o desempenho. Além disso, você pode obter pausas notáveis ​​usando tamanhos de heap> 1 Gb. Isso pode ser desagradável se houver alguma coisa em tempo quase real acontecendo, em um cluster ou grade, um processo java pode não responder e ser descartado do cluster.

No entanto, hoje em dia, os aplicativos de servidor (freqüentemente construídos sobre estruturas inchadas ;-)) exigem muito mais do que 4Gb.

Uma solução para esses requisitos de memória é 'descarregar' partes dos objetos para o heap não-java (alocado diretamente no SO). Felizmente, o java.nio fornece classes para alocar / ler e escrever diretamente blocos de memória 'não gerenciados' (até arquivos mapeados na memória).

Portanto, é possível alocar grandes quantidades de memória 'não gerenciada' e usá-la para salvar objetos lá. Para salvar objetos arbitrários na memória não gerenciada, a solução mais viável é o uso de serialização. Isso significa que o aplicativo serializa objetos na memória fora da pilha; posteriormente, o objeto pode ser lido usando a desserialização.

O tamanho do heap gerenciado pela VM java pode ser pequeno, para que as pausas do GC estejam no milésimo de mil, todo mundo está feliz e pronto.

É claro que o desempenho de um buffer fora do heap depende principalmente do desempenho da implementação de serialização. Boas notícias: por algum motivo, a serialização FST é bastante rápida :-).

Cenários de uso de amostra:

  • Cache de sessão em um aplicativo de servidor. Use um arquivo de memória mapeada para armazenar gigabytes de sessões de usuário (inativas). Depois que o usuário faz login no seu aplicativo, você pode acessar rapidamente dados relacionados ao usuário sem precisar lidar com um banco de dados.
  • Armazenamento em cache de resultados computacionais (consultas, páginas html, ..) (aplicável apenas se a computação for mais lenta que a desserialização do objeto de resultado ofc).
  • persistência muito simples e rápida usando arquivos mapeados na memória

Editar: Em alguns cenários, pode-se escolher algoritmos mais sofisticados de Coleta de Lixo, como ConcurrentMarkAndSweep ou G1, para oferecer suporte a pilhas maiores (mas isso também tem limites além de pilhas de 16 GB). Há também uma JVM comercial com GC (azul) aprimorado e sem pausas disponível.


4
"aloque grandes quantidades de memória 'não gerenciada' e use-a para salvar objetos lá" - você não pode salvar objetos fora da pilha. Você pode armazenar primitivos, agrupá-los em qualquer biblioteca que desejar, mas esses não são objetos. Os dados que você coloca fora da pilha não têm cabeçalho de objeto, você não pode sincronizar, não pode se referir a ele com um campo de referência em outro objeto.
Nitsan Wakart

41

A pilha é o lugar na memória em que vivem os objetos alocados dinamicamente. Se você usou, newentão está na pilha. É o contrário de empilhar espaço, que é onde fica a pilha de funções. Se você tiver uma variável local, essa referência estará na pilha. O heap do Java está sujeito à coleta de lixo e os objetos são utilizáveis ​​diretamente.

O armazenamento fora do heap do EHCache retira seu objeto comum, serializa-o e armazena-o como bytes em um pedaço de memória que o EHCache gerencia. É como armazená-lo em disco, mas ainda está na RAM. Os objetos não são diretamente utilizáveis ​​nesse estado, eles precisam ser desserializados primeiro. Também não está sujeito à coleta de lixo.


Não é simplesmente ainda na pilha, mas como uma forma serializada?
Pacerier

1
como isso a torna mais eficiente?
Pacerier 14/02/12

2
Há várias maneiras. Como os objetos não estão mais no heap Java principal, eles não perdem o tempo do coletor de lixo, não fragmentam o heap da JVM e liberam espaço para outros objetos mais usados. Além disso, como são serializados e provavelmente não são necessários no futuro imediato, podem ser compactados, movidos conforme necessário ou até mesmo paginados em disco.
Adam

1
No ponto de acesso, o tempo de pausa do GC depende diretamente do tamanho do heap. O BigMemory fornece essa troca utilizando RAM em vez de heap, para manter a pausa do GC no mínimo e evitar o custo de IO do acesso ao disco.
Chander Shivdasani


1

A JVM não sabe nada sobre memória fora da pilha. O Ehcache implementa um cache no disco, bem como um cache na memória.


1

Não 100%; no entanto, parece que o heap é um objeto ou conjunto de espaço alocado (na RAM) incorporado à funcionalidade do código, seja o próprio Java ou a funcionalidade mais provável do próprio ehcache, e o Ram fora do heap existe um sistema próprio como bem; no entanto, parece que essa magnitude é uma magnitude mais lenta, pois não é tão organizada, o que significa que ele não pode usar um heap (ou seja, um longo conjunto de espaço de ram) e, em vez disso, usa diferentes espaços de endereço, provavelmente tornando-o um pouco menos eficiente.

Então, é claro que a próxima camada inferior é o próprio espaço no disco rígido.

Como não uso o ehcache, você pode não querer confiar em mim, mas foi o que reuni na documentação deles.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.