Pergunta

Eu estou usando ByteBuffers e FileChannels para escrever dados binários para um arquivo.Ao fazer isso para arquivos grandes, ou, sucessivamente, por vários arquivos, eu tenho um OutOfMemoryError exceção.Eu li em outro lugar que usando Bytebuffers com o NIO é interrompida e deve ser evitado.Faz algum de vocês já se deparou com esse tipo de problema e encontrou uma solução eficiente de guardar grandes quantidades de dados binários em um arquivo em java?

É a jvm opção -XX:MaxDirectMemorySize o caminho a percorrer?

Foi útil?

Solução

Eu diria que não criar uma enorme ByteBuffer que contém TODOS os dados de uma só vez.Criar uma muito menor ByteBuffer, preenchê-lo com dados e, em seguida, escrever dados para o FileChannel.Em seguida, repor a ByteBuffer e continue até que todos os dados são gravados.

Outras dicas

Confira Java Mapeada Bytes Buffers, também conhecida como 'direta'buffers.Basicamente, este mecanismo usa o sistema operacional de paginação da memória virtual do sistema para criar um mapa do seu buffer directamente para o disco.O sistema operacional irá gerenciar mover os bytes de/para o disco e a memória auto-magicamente, muito rapidamente, e você não terá que se preocupar sobre como alterar as opções de máquina virtual.Isso também irá permitir que você tire proveito de NIO para um melhor desempenho do que os tradicionais java baseado em fluxo de e/s, sem qualquer estranho hacks.

A apenas duas patilhas que eu posso pensar são:

  1. No sistema de 32 bits, você está limitado a um pouco menos de 4GB total para todos os mapeada bytes buffers.(Que é, na verdade, um limite para a minha aplicação, e agora eu executar em arquiteturas de 64 bits.)
  2. Implementação da JVM específica e não uma exigência.Eu uso o Sun JVM e não há problemas, mas YMMV.

Kirk Pepperdine (um pouco famoso desempenho de Java guru) está envolvido com um site, www.JavaPerformanceTuning.com, que tem mais alguns MBB detalhes: NIO Dicas de Desempenho

Se você acessar arquivos em um de modo aleatório (ler aqui, ignorar, escrever, voltar), então você tem um problema ;-)

Mas se você só gravar arquivos grandes, você deve sério considere o uso de fluxos. java.io.FileOutputStream pode ser usado diretamente para gravar o arquivo de byte após byte ou envolvidos em qualquer outro fluxo (i.e. DataOutputStream, ObjectOutputStream) por conveniência da escrita flutua, ints, Seqüências de caracteres ou mesmo serializeable objetos.Aulas semelhantes existem para a leitura de arquivos.

Fluxos de oferecer-lhe comodidade de manipulação arbitrariamente arquivos grandes em (quase) arbitrariamente pequena de memória.Eles são os preferidos forma de acessar o sistema de arquivos na grande maioria dos casos.

Usando o transferFrom método deverá ajudar com isso, supondo que você escrever para o canal de forma incremental e não todos de uma vez como respostas anteriores também se destacam.

Isso pode dependem do JDK fornecedor e a versão.

Há um bug no GC em alguns Sun Jvm.A falta de memória direto não vai disparar um GC no heap principal, mas o direct memory é preso por lixo direto ByteBuffers no heap principal.Se a pilha está quase vazio que não pode ser coletadas por um longo tempo.

Isso pode queimá-lo, mesmo se você não estiver usando direto buffers em seu próprio país, porque a JVM pode ser a criação directa de buffers em seu nome.Por exemplo, escrever um direto não ByteBuffer para um SocketChannel cria direta do buffer sob o cobre para uso real da operação de e/S.

A solução é usar um pequeno número de direto buffers de si mesmo, e mantê-los ao redor para reutilização.

Os dois anteriores, as respostas parecem bastante razoáveis.Quanto a saber se a opção de linha de comando irá funcionar, depende de quão rapidamente o seu uso de memória atinge o limite.Se você não tem o suficiente de memória ram e memória virtual disponível para, no mínimo, o triplo de memória disponível, em seguida, você precisará usar um dos alternativo sugestões dadas.

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