Файл сервлета Java Загрузка изображений - эффективен ли код или допускает утечку памяти? - PullRequest
2 голосов
/ 09 марта 2012

Мой сервлет выполняет следующие действия для файла, переданного для загрузки через мою страницу JSP.

Шаг 1 - получить файл, всегда его изображение
Шаг 2 - проверьте, нужно ли изменить его размер
Шаг 2a - если нужно изменить размер, сделайте это
Шаг 3 - также измените размер и создайте размер миниатюры
Шаг 4 - сохранить новое измененное изображение в папке на сервере
Шаг 5 - сохранить эскиз изображения в папке на сервере

Наибольший размер изображения (по запросу моего клиента), который сервлет примет для обработки, составляет 3900 x 3900 ... Я знаю, это огромно! Но это то, что хочет клиент.

Я поставил сервлет на свой tomcat на своем vps для тестирования, и я вижу довольно серьезное потребление памяти.

Пределы памяти VPS
Я получаю 316 МБ памяти. При новом перезапуске Tomcat объем памяти составляет около 108 МБ. VPS также работает на сервере Apache.
Apache , с Tomcat STOPPED использует 45 МБ, поэтому Tomcat занимает 63 МБ при первом запуске.

Tomcat.conf - файл имеет следующий набор для кучи.

# Initial Java Heap Size (in MB)
wrapper.java.initmemory=100

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=128

Как только я запускаю процесс загрузки изображения - отправляя файл изображения через форму на странице JSP - сервлет берет верх, выполняя шаги, которые я описал выше.

Я использую то же изображение, чтобы проверить вещи. Размер изображения составляет 3872 x 2592 пикселя, а его размер равен 2,53 МБ.

Я отправляю это изображение около 5 раз. Каждая загрузка занимает до минуты или более для завершения.

Результаты теста

1 изображение: память = 150 МБ
2 изображения: память = 179 МБ
3 изображение: 179,8
4 изображение: 188,8
5 изображение: 189,3

Почему такой скачок после загрузки изображения, которое составляет всего 2,53 МБ? Я не понимаю Когда память падает, она падает немного. Я загрузил другое изображение после первых 5, и память пошла в 188,8.

Есть ли что-то неэффективное в моем коде? Я позаботился о том, чтобы закрыть все потоки, или, по крайней мере, я почти уверен, что сделал.

Любой вклад приветствуется.



Мой сервлет загрузки и изменения размера

public void addPhoto(Statement stmt, HttpServletRequest req, HttpServletResponse res, HttpSession session) {

            BufferedInputStream bis = null; 
            BufferedImage bufimg = null;
            BufferedImage resized = null;
            ByteArrayOutputStream bytestream = null;
            BufferedOutputStream bos = null;
            FileOutputStream fos = null;

    try {

            String ImageMain = "";
            String ImageThumb = "";                

            String dbShortPathMain = "images/gallery/";             
            String dbShortPathThumb = "images/gallery/";                


       String fileNameToLowerCase = "";
       String fileExtension = "";

       byte[] newimage = null;   

       boolean isPart = ServletFileUpload.isMultipartContent(req);

       if(isPart) {


         FileItemFactory factory = new DiskFileItemFactory();

         ServletFileUpload fileupload = new ServletFileUpload(factory);

         java.util.List items = fileupload.parseRequest(req);

         Iterator it = items.iterator();

         while(it.hasNext()) { //while1                                

                FileItem item = (FileItem)it.next();    
                String fieldValue = item.getName(); 

                if(!item.isFormField()) {

                    String fieldName = item.getFieldName();                                             

                    if(fieldName.equals("ImageMain")) { //10

                          //--------------------------
                          //continue processing upload
                          //field wasn't blank
                          //---------------------------
                          // Create a FileItem object to access the file.
                          File f = new File(fieldValue); 

                          // Get content type by filename.
                          String contentType = getServletContext().getMimeType(f.getName());                                  
                            if(contentType == null) contentType = "none";

                    if(!contentType.startsWith("image")) {
                       appendToURL += "&notfile=y";                             
                      } else {
                          //check size                          
                            bis = new BufferedInputStream(item.getInputStream());                       

                            //BufferedImage
                            bufimg = ImageIO.read(bis);                                         

                            //check size of image 
                            int img_width = bufimg.getWidth();
                            int img_height = bufimg.getHeight();

                            //not accepting images larger than 3900 x 3900
                            if(img_width > 3900 || img_height > 3900) { 
                               appendToURL += "&filesize=y";                                
                             } else {                            

                              //------------------------------------------
                              //  R E S I Z E  &   U P L O A D   F I L E 
                              //------------------------------------------
                                //#### STEP 1 - make size (600 max width) image #### 
                                double scale = (double)maxLargeImageSize/(double)img_width;                             

                                Image sized = getScaledInstanceAWT(bufimg, scale, Image.SCALE_SMOOTH);

                                //convert image to BufferedImage
                                resized = toBufferedImage(sized, BufferedImage.TYPE_INT_RGB);                                   

                                bytestream = new ByteArrayOutputStream();       

                                //make file name characters all lowercase, and extract extension (.jpg)
                                fileNameToLowerCase = fieldValue.toLowerCase();                     
                                fileExtension = fileNameToLowerCase.substring(fileNameToLowerCase.indexOf(".")+1,fileNameToLowerCase.length());

                                //initialize buffer output stream for efficiency                 
                                //BufferedOutputStream
                                bos = new BufferedOutputStream(bytestream);

                                //W R I T E image to BufferedOutputStream and ByteArrayOutputStream
                                if(fileExtension.equals("png")) 
                                   ImageIO.write(resized,"png",bos);                             

                                if(fileExtension.equals("jpg"))             
                                   ImageIO.write(resized,"jpg",bos);                             

                                if(fileExtension.equals("jpeg"))                
                                   ImageIO.write(resized,"jpeg",bos);                            

                                if(fileExtension.equals("gif"))
                                   ImageIO.write(resized,"gif",bos);        

                                if(fileExtension.equals("bmp"))
                                   ImageIO.write(resized,"bmp",bos);                                   

                                // Flush ByteArrayOutputStream                              
                                bytestream.flush();         

                                //convert the bytes in stream to byte array
                                //byte[]
                                newimage = bytestream.toByteArray();                                                                            

                                //specify the file name

                                ImageMain = FileUploadPath+"/thenewfile."+fileExtension;
                                dbShortPathMain += cat+"/thenewfile."+fileExtension;

                                fos = new FileOutputStream(ImageMain);              

                                fos.write(newimage);

                                fos.flush();                                    

                                //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                                //#### STEP 2 - make Thumb size (140 max width) image ####
                                scale = (double)maxThumbImageSize/(double)img_height;                               

                                sized = getScaledInstanceAWT(bufimg, scale, Image.SCALE_SMOOTH);

                                //convert image to BufferedImage
                                resized = toBufferedImage(sized, BufferedImage.TYPE_INT_RGB);

                                //used to convert the new image to bytes so it can be put into db
                                //ByteArrayOutputStream
                                bytestream = new ByteArrayOutputStream();                       

                                //initialize buffer output stream for efficiency                 
                                //BufferedOutputStream
                                bos = new BufferedOutputStream(bytestream);

                                //W R I T E image to BufferedOutputStream and ByteArrayOutputStream
                                if(fileExtension.equals("png")) 
                                   ImageIO.write(resized,"png",bos);                             

                                if(fileExtension.equals("jpg"))             
                                   ImageIO.write(resized,"jpg",bos);                             

                                if(fileExtension.equals("jpeg"))                
                                   ImageIO.write(resized,"jpeg",bos);                            

                                if(fileExtension.equals("gif"))
                                   ImageIO.write(resized,"gif",bos);        

                                if(fileExtension.equals("bmp"))
                                   ImageIO.write(resized,"bmp",bos);                                   

                                // Flush ByteArrayOutputStream                              
                                bytestream.flush();         

                                //convert the bytes in stream to byte array
                                //byte[]
                                newimage = bytestream.toByteArray();                                                                            

                                //specify the file name
                                ImageThumb = FileUploadPath+"/newfilethumb."+fileExtension;
                                dbShortPathThumb += cat+"/newfilethumb."+fileExtension;

                                fos = new FileOutputStream(ImageThumb);             

                                fos.write(newimage);

                                fos.flush();                                
                                //#### end large size ####  

                              //---------------------------------------

                        }

                        }                     


                      }                           

                  }//isFormField

                  }//while  

                }//isPart

    }//try
    catch(Exception e) {}

     finally {
    if (bis != null) try { bis.close(); } catch (IOException logOrIgnore) {}
    if (bytestream != null) try { bytestream.close(); } catch (IOException logOrIgnore) {}
    if (bos != null) try { bos.close(); } catch (IOException logOrIgnore) {}
    if (fos != null) try { fos.close(); } catch (IOException logOrIgnore) {}
    }       

}//addPhoto


//-----------------------------------------------------------
//R E S I Z I N G   I M A G E   M E T H O D S
//-----------------------------------------------------------
        public BufferedImage toBufferedImage(Image image, int type) {
            BufferedImage result = null;
            try {
                    int w = image.getWidth(null);
                    int h = image.getHeight(null);
                    result = new BufferedImage(w, h, type);
                    Graphics2D g = result.createGraphics();
                    g.drawImage(image, 0, 0, null);
                    g.dispose();                    
                }//try
                catch(Exception e) {}

                return result;
        }//end

        public Image getScaledInstanceAWT(BufferedImage source, double scale, int hint) {        
            Image newimage = null;
            try {           
                    int w = (int) (source.getWidth() * scale);
                    int h = (int) (source.getHeight() * scale);        
                    newimage = source.getScaledInstance(w, h, hint);
                }//try
                catch(Exception e) {}               

                return newimage;
        }//end
...