2013-05-31 3 views
1

Я пытаюсь загрузить видео на сервер Tomcat, но после загрузки одного видео, которое я получил под ошибкой:java.lang.OutOfMemoryError: Java куча пространства: пытаться загружать видео

Error Log:

org.apache.jasper.JasperException: An exception occurred processing JSP page /SaveVideos.jsp at line 34 

31:   pos = file.indexOf("\n", pos) + 1; 
32:   int boundaryLocation = file.indexOf(boundary, pos) - 4; 
33:   int startPos = ((file.substring(0, pos)).getBytes()).length; 
34:   int endPos = ((file.substring(0, boundaryLocation)).getBytes()).length; 
35:   
36:  // String pathToFile = this.getServletContext().getRealPath(request.getPathInfo()); 
37:   File ff = new File(this.getServletContext().getRealPath("/")+"videos/"+ saveFile); 


Stacktrace: 
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:524) 
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:417) 
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320) 
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803) 


root cause 

javax.servlet.ServletException: java.lang.OutOfMemoryError: Java heap space 
    org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:850) 
    org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:779) 
    org.apache.jsp.SaveVideos_jsp._jspService(SaveVideos_jsp.java:138) 
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803) 
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393) 
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320) 
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803) 


root cause 

java.lang.OutOfMemoryError: Java heap space 
    java.lang.StringCoding$StringEncoder.encode(StringCoding.java:232) 
    java.lang.StringCoding.encode(StringCoding.java:272) 
    java.lang.StringCoding.encode(StringCoding.java:284) 
    java.lang.String.getBytes(String.java:987) 
    org.apache.jsp.SaveVideos_jsp._jspService(SaveVideos_jsp.java:90) 
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803) 
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393) 
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320) 
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803) 

SaveVideo.jsp:

<%@ page import="java.io.*,java.sql.*,java.util.zip.*"%> 
<%@ page import="jdbc.DBConnection"%> 
<% 
    String saveFile = ""; 
    String contentType = request.getContentType(); 
    if ((contentType != null) 
      && (contentType.indexOf("multipart/form-data") >= 0)) { 
     DataInputStream in = new DataInputStream(request 
     .getInputStream()); 
     int formDataLength = request.getContentLength(); 
     byte dataBytes[] = new byte[formDataLength]; 
     int byteRead = 0; 
     int totalBytesRead = 0; 
     while (totalBytesRead < formDataLength) { 
      byteRead = in.read(dataBytes, totalBytesRead, 
      formDataLength); 
      totalBytesRead += byteRead; 
     } 
     String file = new String(dataBytes); 
     saveFile = file.substring(file.indexOf("filename=\"") + 10); 
     saveFile = saveFile.substring(0, saveFile.indexOf("\n")); 
     saveFile = saveFile.substring(saveFile.lastIndexOf("\\") + 1, 
     saveFile.indexOf("\"")); 
     int lastIndex = contentType.lastIndexOf("="); 
     String boundary = contentType.substring(lastIndex + 1, 
     contentType.length()); 
     int pos; 
     pos = file.indexOf("filename=\""); 
     pos = file.indexOf("\n", pos) + 1; 
     pos = file.indexOf("\n", pos) + 1; 
     pos = file.indexOf("\n", pos) + 1; 
     int boundaryLocation = file.indexOf(boundary, pos) - 4; 
     int startPos = ((file.substring(0, pos)).getBytes()).length; 
     int endPos = ((file.substring(0, boundaryLocation)).getBytes()).length; 

    // String pathToFile = this.getServletContext().getRealPath(request.getPathInfo()); 
     File ff = new File(this.getServletContext().getRealPath("/")+"videos/"+ saveFile); 

     FileOutputStream fileOut = new FileOutputStream(ff); 
     fileOut.write(dataBytes, startPos, (endPos - startPos)); 
     fileOut.flush(); 
     fileOut.close(); 
%><br> 
<table border="2"> 
    <tr> 
     <td><b>You have successfully upload the file:</b> <% 
     response.sendRedirect("HomePage.jsp"); 

%> 
     </td> 
    </tr> 
</table> 
<% 
DBConnection db_con = new DBConnection(); 
PreparedStatement psmnt = null; 
     try { 
      Connection con = db_con.getConnection(); 

       psmnt = con.prepareStatement("insert into video_tbl(Video_name ) values(?)"); 

      psmnt.setString(1,saveFile); 

      int s = psmnt.executeUpdate(); 
      if (s > 0) { 
     System.out.println("Uploaded successfully !"); 
      } else { 
     System.out.println("Error!"); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
%> 

конфигурации

VM Arguments : 
-Xms1024m -Xmx1024m 
+4

Почему бы не потоковое загружать на диск, а вместо того, чтобы принимать их все в памяти? Существует множество фреймворков, которые сделают это для вас. Или, в вашем случае, не читайте все данные в 'while (totalBytesRead Rup

ответ

6

Есть две связанные проблемы с вашим кодом:

  1. Вы буферные весь загруженный документ (видео) в памяти. Это занимает много памяти и является наиболее вероятной причиной ваших OOME.

  2. , относящиеся к предыдущему, если fileContent больше 2^32 - 1 байт (т.е. чуть более 2Gb) код потерпит неудачу, потому что длина содержимого не будет соответствовать в int, и вы не можете выделить массив с более 2^32 - 1 элементов.

Что вам нужно сделать, это что-то вроде этого:

  • Оберните InputStream в BufferedInputStream а не DataInputStream.
  • Прочитайте и скопируйте данные «конверт» данных формы байта за один раз, используя read(), пока не достигнете символов новой строки. Затем переведите каждую строку в строку, чтобы выполнить синтаксический анализ.
  • После того, как вы дойдете до начала содержимого файла, прочитайте байт одновременно, ища пограничную последовательность, и записывая (неграничные) байты данных в выходной файл через BufferedOutputStream.

еще лучше, если бы вы смотрели, вы должны быть в состоянии найти существующие компоненты для обработки Multiparts.


У вас также возникла проблема, заключающаяся в том, что у вас есть значительная «бизнес-логика», встроенная в ваш JSP как код сценария. Это плохая практика. Вы должны сделать бизнес-логику (запросы и обновления базы данных, загрузку файлов и т. Д.) В сервлете и просто использовать JSP для вывода вывода.

0

Вы создаете видео в памяти дважды: 1. байт dataBytes [] = новый байт [formDataLength]; 2. String file = new String (dataBytes);

Вы можете изменить это ...

3

Вы можете переписать код так, чтобы он непосредственно потоков из входного потока в файл. Для этого требуется только небольшой буфер.

Смежные вопросы