Vi no stackoverflow a dica pra dar um flush() e setar a variável pra null pra poder ser coletada pelo GC,mas o erro persiste.Alguem ja passou por isso?
Você vai precisar de jvisualvm para identificar o que está criando o leak. a primeira vista aí parece que não tem leak. Qual o tamanho das imagens?
R
raf4ever
A classe java.io.File não tem esse método close,eu estou setando a referência pra null,devia ser suficiente,não?
J
juliocbq
eu percebi ali, por isso editei o post.
R
raf4ever
O tamanho varia de 1 a 4 mb.
Eu configurei o Eclipse pra usar o Visual VM Launcher,mas não to sabendo como executar.
J
juliocbq
o coletor de lixo não responde ao que você faz, pois ele é automático. Dá uma olhada com o jvisualvm e veja se é realmente a imagem que está causando o leak. E qual o tamanho delas?
J
juliocbq
O tamanho varia de 1 a 4 mb.
Eu configurei o Eclipse pra usar o Visual VM Launcher,mas não to sabendo como executar.
Abre o jvvm, executa o programa e manda jvvm ler. Então você pode fazer um profiler.
J
juliocbq
O tamanho varia de 1 a 4 mb.
Eu configurei o Eclipse pra usar o Visual VM Launcher,mas não to sabendo como executar.
vc quer subir 2000 imagens de 4mb com java? Vai precisar otimizar bem esse algoritmo aí.
Faz o seguinte, eu imagino que não seja um leak. Aumenta o tamanho do heap da máquina virtual para mais ou menos 1gb. Talvez seja suficiente para subir essas imagens aí.
R
raf4ever
Minha dúvida é:Executei o Visual VM,como faço pra ele ‘escutar’ a minha aplicação e gerar o heap dump relativo a ele?
R
raf4ever
Encontrei aqui.
R
raf4ever
Aumentei o heap size pra 1gb mas tbm estourou.
J
juliocbq
faz um teste com imagens bem menores. Aprox. 100kb. e vê se elas sobem sem quebrar seu programa. Se subir você vai ter que estudar esse seu problema com mais calma, desenvolvendo um algoritmo mais robusto. Eu nunca precisei subir imagens com esse peso para memória. É “jpeg”?
Outra coisa. Pode ser que gc nem esteja tendo tempo de desalocar as imagens.
Stringcaminho=pastaBackup+File.separator+p.getNomeArquivo();Filef=newFile(caminho);Imageimg=Toolkit.getDefaultToolkit().createImage(bytesFromFile(f));p.setImage(img);publicstaticbyte[]bytesFromFile(Filefile)throwsIOException{FileInputStreamis=newFileInputStream(file);longlength=file.length();Integerlen=newInteger(5000000);//if (length > Integer.MAX_VALUE) {if(length>=len){addErrorMessage("Desculpe! Seu arquivo é muito grande para o servidor.");System.exit(0);}byte[]bytes=newbyte[(int)length];intoffset=0;intnumRead=0;while(offset<bytes.length&&(numRead=is.read(bytes,offset,bytes.length-offset))>=0){offset+=numRead;}if(offset<bytes.length){thrownewIOException("Não foi possível ler o arquivo completamente "+file.getName());}is.close();returnbytes;}
Stringcaminho=pastaBackup+File.separator+p.getNomeArquivo();Filef=newFile(caminho);Imageimg=Toolkit.getDefaultToolkit().createImage(bytesFromFile(f));p.setImage(img);publicstaticbyte[]bytesFromFile(Filefile)throwsIOException{FileInputStreamis=newFileInputStream(file);longlength=file.length();Integerlen=newInteger(5000000);//if (length > Integer.MAX_VALUE) {if(length>=len){addErrorMessage("Desculpe! Seu arquivo é muito grande para o servidor.");System.exit(0);}byte[]bytes=newbyte[(int)length];intoffset=0;intnumRead=0;while(offset<bytes.length&&(numRead=is.read(bytes,offset,bytes.length-offset))>=0){offset+=numRead;}if(offset<bytes.length){thrownewIOException("Não foi possível ler o arquivo completamente "+file.getName());}is.close();returnbytes;}
Você vai precisar diminuir essas imagens para carregá-las de qualquer maneira.
O que deve estar acontecendo aí é que essas imagens já estão codificadas e mesmo assim são enormes.
Essa solução não vai funcionar mesmo.
R
raf4ever
Alguma idéia sobre isso?Habilitar Gzip no Tomcat poderia ser uma solução?
J
juliocbq
raf4ever:
Você vai precisar diminuir essas imagens para carregá-las de qualquer maneira.
Alguma idéia sobre isso?Habilitar Gzip no Tomcat poderia ser uma solução?
você precisa ter certeza que essas imagens vão chegar pro java em um tamanho apropriado pra pilha dele. Mas não adianta ela chegar zipada, porque você vai precisar descompacta-la antes de carregar o bitmap e aí você cai no mesmo problema.
Precisa arranjar um jeito de gerar thumbs delas.
R
raf4ever
Bem,eu fiz um teste aqui mas não consegui entender o que aconteceu:
BufferedImagefoto;ByteArrayInputStreaminputStream;Filef;Stringcaminho;for(Produtop:listaProdutos){if(p.getNomeArquivo()!=null){caminho=pastaBackup+File.separator+p.getNomeArquivo();f=newFile(caminho);inputStream=newByteArrayInputStream(bytesFromFile(f));foto=ImageIO.read(inputStream);p.setFile(foto);inputStream=null;caminho=null;if(f!=null)f=null;if(foto!=null)foto=null;System.gc();System.gc();System.gc();System.out.println("TOTAL DE MEMORIA::"+Runtime.getRuntime().totalMemory());System.out.println("MEMORIA USADA::"+Runtime.getRuntime().freeMemory());}
A ultima impressão foi:
TOTAL DE MEMORIA::259522560
MEMORIA USADA::14934512
Dessa forma tbm estourou a pilha,mas dessa vez eu n entendi porque,já que o GC parece estar funcionando.
J
juliocbq
raf4ever:
Bem,eu fiz um teste aqui mas não consegui entender o que aconteceu:
BufferedImagefoto;ByteArrayInputStreaminputStream;Filef;Stringcaminho;for(Produtop:listaProdutos){if(p.getNomeArquivo()!=null){caminho=pastaBackup+File.separator+p.getNomeArquivo();f=newFile(caminho);inputStream=newByteArrayInputStream(bytesFromFile(f));foto=ImageIO.read(inputStream);p.setFile(foto);inputStream=null;caminho=null;if(f!=null)f=null;if(foto!=null)foto=null;System.gc();System.gc();System.gc();System.out.println("TOTAL DE MEMORIA::"+Runtime.getRuntime().totalMemory());System.out.println("MEMORIA USADA::"+Runtime.getRuntime().freeMemory());}
A ultima impressão foi:
TOTAL DE MEMORIA::259522560
MEMORIA USADA::14934512
Dessa forma tbm estourou a pilha,mas dessa vez eu n entendi porque,já que o GC parece estar funcionando.
O problema não é o GC, mas as imagens que são grandes demais para a plilha da máquina virtual. Não existe memory leak aí.
invocar System.gc() não obriga o mesmo a ser executado. Esse método não faz diferença alguma.
Você precisa passar imagens menores(bem menores).
R
raf4ever
juliocbq:
raf4ever:
Bem,eu fiz um teste aqui mas não consegui entender o que aconteceu:
BufferedImagefoto;ByteArrayInputStreaminputStream;Filef;Stringcaminho;for(Produtop:listaProdutos){if(p.getNomeArquivo()!=null){caminho=pastaBackup+File.separator+p.getNomeArquivo();f=newFile(caminho);inputStream=newByteArrayInputStream(bytesFromFile(f));foto=ImageIO.read(inputStream);p.setFile(foto);inputStream=null;caminho=null;if(f!=null)f=null;if(foto!=null)foto=null;System.gc();System.gc();System.gc();System.out.println("TOTAL DE MEMORIA::"+Runtime.getRuntime().totalMemory());System.out.println("MEMORIA USADA::"+Runtime.getRuntime().freeMemory());}
A ultima impressão foi:
TOTAL DE MEMORIA::259522560
MEMORIA USADA::14934512
Dessa forma tbm estourou a pilha,mas dessa vez eu n entendi porque,já que o GC parece estar funcionando.
O problema não é o GC, mas as imagens que são grandes demais para a plilha da máquina virtual. Não existe memory leak aí.
invocar System.gc() não obriga o mesmo a ser executado. Esse método não faz diferença alguma.
Você precisa passar imagens menores(bem menores).
Ok,entendi.Mas a minha duvida é:Pq com essa forma de implementação o consumo de memória está bem abaixo do que antes,quando eu estava usando ImageIo.read()?
J
juliocbq
raf4ever:
juliocbq:
raf4ever:
Bem,eu fiz um teste aqui mas não consegui entender o que aconteceu:
BufferedImagefoto;ByteArrayInputStreaminputStream;Filef;Stringcaminho;for(Produtop:listaProdutos){if(p.getNomeArquivo()!=null){caminho=pastaBackup+File.separator+p.getNomeArquivo();f=newFile(caminho);inputStream=newByteArrayInputStream(bytesFromFile(f));foto=ImageIO.read(inputStream);p.setFile(foto);inputStream=null;caminho=null;if(f!=null)f=null;if(foto!=null)foto=null;System.gc();System.gc();System.gc();System.out.println("TOTAL DE MEMORIA::"+Runtime.getRuntime().totalMemory());System.out.println("MEMORIA USADA::"+Runtime.getRuntime().freeMemory());}
A ultima impressão foi:
TOTAL DE MEMORIA::259522560
MEMORIA USADA::14934512
Dessa forma tbm estourou a pilha,mas dessa vez eu n entendi porque,já que o GC parece estar funcionando.
O problema não é o GC, mas as imagens que são grandes demais para a plilha da máquina virtual. Não existe memory leak aí.
invocar System.gc() não obriga o mesmo a ser executado. Esse método não faz diferença alguma.
Você precisa passar imagens menores(bem menores).
Ok,entendi.Mas a minha duvida é:Pq com essa forma de implementação o consumo de memória está bem abaixo do que antes,quando eu estava usando ImageIo.read()?
É a mesma coisa. Você pode até remover System.gc() nesse bloco de código porque é inútil. Eu imagino que pode até atrapalhar o desempenho da aplicação.
Como você chamou o coletor ele pode limpar o lixo nesse ponto e reduzir alguma coisa que estava alocada(mas é pouca diferença). Se você olhar aí na parte de cpu da jvisualvm vai ver que em termos de processamento seu programa está pior( porque você força pausa no software para coleta de lixo dentro desse laço). Se você já atribuiu null o gc já marca o bloco para ser removido. Não precisa invocar System.gc().
O outro ponto que foi citado na solução do stack overflow é que ImageIO.read() carrega um DIB ao invés de uma imagem codificada. Por isso o resultado de ImageIO.read() ocupa mais espaço.