title: Java Servlet File Upload of images - is the code efficient or allowing for memory leak?
body: <p>My servlet does the following for a file submitted for upload through my JSP page.</p>
  
  <p><strong>Step 1</strong> - get the file, its always an image
  <br/><strong>Step 2</strong> - check if it needs to be resized
  <br/><strong>Step 2a</strong> - if needs resize, do it
  <br/><strong>Step 3</strong> - also resize and create thumbnail size 
  <br/><strong>Step 4</strong> - store new resized image in folder on server
  <br/><strong>Step 5</strong> - store thumbnail image in folder on server</p>
  
  <p>The largest image size (per my client's request) the servlet will accept for processing is a 3900 x 3900...I know, that is huge! But that's what the client wants.</p>
  
  <p>I've put the servlet up on my tomcat on my vps for testing and I'm seeing some pretty serious memory consumption.</p>
  
  <p><strong>VPS Memory Limits</strong>
  <br/>I get 316MB of memory. With a fresh restart on Tomcat, memory is at about 108MB. The VPS is also running Apache server. 
  <br/><strong>Apache</strong>, with Tomcat STOPPED is using 45MB, so Tomcat is taking up 63MB on initial startup.</p>
  
  <p><strong>Tomcat.conf</strong> - file is has the following set for the heap.</p>
  
  <pre><code># Initial Java Heap Size (in MB)
  wrapper.java.initmemory=100
  
  # Maximum Java Heap Size (in MB)
  wrapper.java.maxmemory=128
  </code></pre>
  
  <p>Once I run the image upload process - submitting an image file through a form on a JSP page - the servlet takes over from there doing the Steps I described above.</p>
  
  <p>I use the same image to test things out. The image is sized at 3872 x 2592 pixels and it equates to 2.53MB.</p>
  
  <p>I submit this image about 5 times. Each upload takes up to a minute, or more to complete. </p>
  
  <h2>The Test Results</h2>
  
  <p>1 image : memory=150mb
  <br/>
  2 image : memory = 179mb
  <br/>
  3 image : 179.8
  <br/>
  4 image: 188.8
  <br/>
  5 image: 189.3</p>
  
  <p><strong>Why such a jump after uploading an image that is only 2.53MB?</strong>
  I don't get it.  When the memory drops, it drops slightly. I uploaded another image after the first 5, and the memory went to 188.8.</p>
  
  <p><strong>Is there something inefficient about my code?</strong> I made sure to close all the streams, or at least I'm pretty sure I did. </p>
  
  <p><strong>Any input is greatly appreciated.</strong></p>
  
  <p><br/><br/></p>
  
  <h2>My Image Upload and Resizing Servlet</h2>
  
  <pre><code>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 += "&amp;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 &gt; 3900 || img_height &gt; 3900) { 
                                 appendToURL += "&amp;filesize=y";                                
                               } else {                            
  
                                //------------------------------------------
                                //  R E S I Z E  &amp;   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
  </code></pre>