Existem alguns projetos por aí que utilizam os MappedByteBuffers retornados pelo FileChannel.map() do Java como uma forma de ter IPCs de memória compartilhada entre JVMs no mesmo host (veja Chronicle Queue, Aeron IPC, etc.). Tanto quanto eu posso dizer, esta api fica em cima da chamada mmap. Entretanto, a implementação do Java não permite mapeamentos anônimos (sem suporte a arquivos).
Minha pergunta é, em Java (1.8) e Linux (3.10), os MappedByteBuffers são realmente necessários para implementar IPC de memória compartilhada, ou qualquer acesso a um arquivo comum forneceria a mesma funcionalidade? (Esta pergunta não se refere à implicação de desempenho do uso ou não de um MappedByteBuffer)
Aqui está o meu entendimento:
- Quando o Linux carrega um arquivo do disco, ele copia o conteúdo desse arquivo para páginas na memória. Essa região da memória é chamada de cache de páginas. Até onde posso dizer, ela faz isso independentemente do método Java (FileInputStream.read(), RandomAccessFile.read(), FileChannel.read(), FileChannel.map()) ou método nativo é usado para ler o arquivo (obsevado com free e monitorando o valor cache).
- Se outro processo tentar carregar o mesmo arquivo (enquanto ele ainda estiver residente no cache) o kernel detecta isso e não precisa recarregar o arquivo. Se a cache da página ficar cheia, as páginas serão despejadas - as que estiverem sujas serão escritas de volta para o disco. (Páginas também são escritas de volta se houver uma descarga explícita no disco, e periodicamente, com uma thread do kernel).
- Ter um arquivo (grande) já no cache é um aumento de desempenho significativo, muito mais do que as diferenças baseadas em quais métodos Java usamos para abrir/ler esse arquivo.
- Um programa em C chamando o sistema de chamada mmap pode fazer um mapeamento ANÓNIMO, que essencialmente aloca páginas no cache que não são suportadas por um arquivo real (então não há necessidade de emitir gravações reais no disco), mas Java não parece oferecer isso (o mapeamento de um arquivo em tmpfs realizaria a mesma coisa?)
- Se um arquivo é carregado usando a chamada de sistema mmap (C) ou via FileChannel.map() (Java), essencialmente as páginas do arquivo (na cache) são carregadas diretamente no espaço de endereços do processo. Usando outros métodos para abrir um arquivo, o arquivo é carregado em páginas que não estão no espaço de endereços do processo, e então os vários métodos para ler/escrever esse arquivo copiam alguns bytes de/para essas páginas em um buffer no espaço de endereços do processo. Há um benefício óbvio de desempenho evitando essa cópia, mas minha pergunta não está relacionada ao desempenho.
Então, em resumo, se eu entendi corretamente - enquanto o mapeamento oferece uma vantagem de desempenho, ele não parece oferecer nenhuma funcionalidade de memória compartilhada que nós ainda não obtemos apenas da natureza do Linux e do cache da página.
Então, por favor, diz-me onde está a minha compreensão.
Obrigado.