Métodos consumindo memória demais!

8 respostas
laelsonc

Olá Senhores !
Seguinte, tenho uma aplicação na web que edita algumas fotos, estou usando dois métodos que estão consumindo demais a memória da minha
hospedagem. Tipo, quando cliente envia as fotos, as vezes toda aplicação trava e não volta até eu reiniciar o Apache. No log do apache foi indicado que é no servlet, e executando a função de imagens.
Os métodos servem para reduzir e colocar marca d'agua nas imagens.
Elas estão ai embaixo, agradeço quem poder analisar para ver onde esta o(s) erro(s).

public static void gerarThumbnail(InputStream inputStream, OutputStream out, int thumbAltura, float quality) throws Exception{

            Image image = null;
            int largura = 0;
            int altura = 0;


            try {
            //Recuperar os valores de LARGURA/ALTURA e ALTERAR no registro da FOTO
            image = ImageIO.read(inputStream);
            largura = image.getWidth(null);
            altura = image.getHeight(null);
            
            
            
            } catch (Exception e) {
            throw new Exception("ERRO ALTERANDO TAMANHO DA IMAGEM " + e);
            }

            try {

            //Fazer a geracao do TumbNail levando em conta o tamanho da ALTURA
            MediaTracker mediaTracker = new MediaTracker(new Container());
            mediaTracker.addImage(image, 0);
            mediaTracker.waitForID(0);

            // determine thumbnail size from WIDTH and HEIGHT
            
            
            double thumbPorcentagem = ((thumbAltura*100.0)/altura)/100.0;
            int thumbLargura = (int)(largura * thumbPorcentagem);
            

            // draw original image to thumbnail image object and
            // scale it to the new size on-the-fly
            BufferedImage thumbImage = new BufferedImage(thumbLargura,thumbAltura, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics2D = thumbImage.createGraphics();
            graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR); //VALUE_INTERPOLATION_BICUBIC - For speed better use RenderingHints.VALUE_INTERPOLATION_BILINEAR
            graphics2D.drawImage(image, 0, 0, thumbLargura, thumbAltura, null);

            // save thumbnail image to OUTFILE
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);

            param.setQuality(quality, false); //The quality argument from the command line is converted from the interval 0 to 100 to the interval 0.0f to 1.0f, because that's what the codec expects (I mostly use 0.75f).
            encoder.setJPEGEncodeParam(param);
            encoder.encode(thumbImage);
            
            inputStream.close();
            out.flush();
            out.close();
            

            } catch (Exception e) {
            throw new Exception("ERRO SALVANDO O THUMBNAIL DA IMAGEM " + e);
            }
            }

Aqui a outra para gerar a marca d'agua.

public static void gerarWatermark(InputStream imagemOriginal, InputStream imagemWatermark, OutputStream imagemGerada,String posicao,float alpha){

            try {

            BufferedImage im = ImageIO.read(imagemOriginal);
            BufferedImage im2 = ImageIO.read(imagemWatermark);
            Graphics2D g = im.createGraphics();            
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
            
            
            //g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, (im.getHeight()-im2.getHeight())/2, null);
            
                       
            // TOP ESQUERDO 
            if(posicao.equals("7")){
            g.drawImage(im2, 0, 0, null); 
                        
            // TOP CENTRO
            }else if(posicao.equals("8")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, 0, null); 
                        
            // TOP DIREITO
            }else if(posicao.equals("9")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth()), 0, null); 
                        
            // CENTRO ESQUERDO
            }else if(posicao.equals("4")){
            g.drawImage(im2, 0, (im.getHeight()-im2.getHeight())/2, null);

            // CENTRO
            }else if(posicao.equals("5")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, (im.getHeight()-im2.getHeight())/2, null);
            
            // CENTRO DIREITO
            }else if(posicao.equals("6")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth()), (im.getHeight()-im2.getHeight())/2, null);
            
            // BASE ESQUERDA
            }else if(posicao.equals("1")){
            g.drawImage(im2, 0, (im.getHeight()-im2.getHeight()), null);

            // BASE CENTRO
            }else if(posicao.equals("2")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, (im.getHeight()-im2.getHeight()), null);
            
            // BASE DIREITA
            }else if(posicao.equals("3")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth()), (im.getHeight()-im2.getHeight()), null);
            }
            
            g.dispose();
            ImageIO.write(im, "jpeg", imagemGerada);
            
            imagemOriginal.close();
            imagemWatermark.close();
            imagemGerada.flush();
            imagemGerada.close();
            
            

            } catch (Exception e) {
            System.out.println(e);
            }
}

A minha hospedagem esta com 256 de memória. E mesmo assim as vezes trava quando os métodos são chamados.
Obs.: O único agravante, fora os métodos, é que a forma que esta sendo enviado os forms é individual e não todos de uma so vez, (para poderem ser quebrados com common Fileupload por exemplo). Elas são enviadas simulando o sistema do Gmail, para um iframe na página e deixando uma msg de "Carregando...". Dai o usuário pode enviar uma, depois vai para outra, para outra...e todas vão sendo carregadas. Num total de até 10.

Bom, vejam se há problemas na função, se sim, mudarei do contrario mudarei a forma de envio de imagens.
Valeu !

Valeu !

8 Respostas

KWill

Pelo que eu pude ver, normalmente tratamento de imagens é uma coisa que costuma consumir uma quantidade razoável de memória mesmo. Dá para tentar reduzir um pouco o consumo de memória RAM configurando a classe utilitária estática para usar cache, chamando na classe “ImageIO” o método “setUseCache(true)”. Lembrar de chamar explicitamente o método “flush()” das classes “Image” e “BufferedImage” quando as imagens não forem mais necessárias na memória também pode ajudar.

Inté.

laelsonc

Então java se torna inviável para pequenas aplicações mesmo.
Porque so tenho um cliente mechendo com isso, e se eu tivesse mais ??? Teria que locar um servidor com 2gb de RAM…
Eu tinha um sistema em PHP que nunca me deu problema com lance de imagens, a GD2 era uma mão na roda.
Agora em JAVA, apesar de haver um mundo de métodos que fazem isso, não encontrei um realmente satisfatório ( esse é o terceiro que tento ).

Obs. Eu não criei esses métodos, só adaptei. Não tenho conhecimento profundo na linguagem, você poderia me dizer como eu poderia mecher neles para de acordo com as dicas que me passou ?

Do mais valeu mesmo !

KWill

laelsonc:
Então java se torna inviável para pequenas aplicações mesmo.
Porque so tenho um cliente mechendo com isso, e se eu tivesse mais ??? Teria que locar um servidor com 2gb de RAM…
Eu tinha um sistema em PHP que nunca me deu problema com lance de imagens, a GD2 era uma mão na roda.
Agora em JAVA, apesar de haver um mundo de métodos que fazem isso, não encontrei um realmente satisfatório ( esse é o terceiro que tento ).

Obs. Eu não criei esses métodos, só adaptei. Não tenho conhecimento profundo na linguagem, você poderia me dizer como eu poderia mecher neles para de acordo com as dicas que me passou ?

Do mais valeu mesmo !

Talvez haja alguma biblioteca nativa que tenha um consumo de memória reduzido e que possa ser usada no lugar do pacote “java.awt.image” para o que você precisa. Ou então já existe alguma biblioteca em puro Java mesmo que consiga fazer o tratamento de imagens que você precisa e que consuma menos memória que o pacote “java.awt.image”. No caso de se usar alguma biblioteca nativa, procure por JNI e/ou por JNA.

Inté.

laelsonc

Alguém conhece algum método customizado ?

Alguém também sabe com eu testar o consumo de memória ? Uso o NetBeans para desenvolvimento.

KWill

laelsonc:
Alguém conhece algum método customizado ?

Alguém também sabe com eu testar o consumo de memória ? Uso o NetBeans para desenvolvimento.

Você pelo menos tentou otimizar o consumo de memória do pacote “java.awt.image” com as dicas que dei? Normalmente, eu sempre chamo o método “dispose()” da classe Graphics e da classe Graphics2D quando essas classes não são necessárias e também chamo o método “flush()” da classe Image e da classe BufferedImage quando essas classes não são mais necessárias. Só essas atitudes costumam liberar para mim uma quantidade razoável de memória rapidamente.

Inté.

laelsonc

Sem querer ser chato, mas daria pra vc me dizer como nos métodos em questão ?

KWill

Normalmente, costumo simplesmente dar toques, explicar alguma coisa e tento mostrar o “caminho das pedras” que deve ser percorrido. Nem sempre escrevo códigos aqui no fórum, pois acredito que essa parte divertida de percorrer o “caminho das pedras” deve ser cumprida por aqueles que buscam soluções para seus problemas, ou estes poderiam ao menos tentar percorrer tal “caminho”.
Pois bem, no método “gerarThumbnail”, faltou chamar o método “dispose()” na instância da classe “Graphics2D” referenciada como “graphics2D” e faltou chamar o método “flush()” na instância da classe “Image” referenciada como “image” e na instância da classe “BufferedImage” referenciada como “thumbImage”. No método “gerarWatermark”, faltou chamar o método “flush()” nas instâncias da classe “BufferedImage” referenciadas como “im” e “im2”.
Uma outra dica, não sei se essa classe “JPEGImageEncoder” que provavelmente provém de alguma biblioteca externa é suficientemente eficiente para o que você precisa.

Inté.

laelsonc

Ok amigo. Obrigado pela gentileza.

Quanto a sua prestatividade, o melhor é sempre seguir suas convicções. Mas as vezes uma ajudinha “mão na roda” vem a calhar, dependendo da urgência e falta de conhecimento do seu próximo. É aquela velha questão, nunca se sabe se quem esta pedindo o faz por preguiça, ou por necessidade numa urgência sincera.

Fique com Deus.

Criado 26 de dezembro de 2008
Ultima resposta 26 de dez. de 2008
Respostas 8
Participantes 2