java.lang.OutOfMemoryError:Java堆空间:尝试上传视频

时间:2013-05-31 09:41:15

标签: java memory-leaks

我正在尝试在tomcat服务器上传视频,但在上传一个视频后我得到了以下错误:

错误日志:

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

3 个答案:

答案 0 :(得分:6)

您的代码存在两个相关问题:

  1. 您正在缓存内存中的整个上传文档(视频)。这会占用大量内存,并且最有可能是您OOME的原因。

  2. 与上一个相关,如果fileContent超过2^32 - 1字节(即超过2Gb),您的代码将失败,因为内容长度不适合int,并且您不能分配超过2^32 - 1个元素的数组。

  3. 你需要做的是这样的事情:

    • InputStream换成BufferedInputStream而不是DataInputStream
    • 使用read()一次一个字节地读取并累积表单数据“信封”数据,直到您到达换行符。然后将每一行转换为字符串以进行解析。
    • 一旦到达文件内容的开头,一次读取一个字节,查找边界序列,并通过BufferedOutputStream将(非边界)数据字节写入输出文件。

    更好的是,如果你看起来你应该能够找到处理多部分的现有组件。


    您还遇到了一个问题,即您在JSP中嵌入了重要的“业务逻辑”作为“scriptlet”代码。这是糟糕的做法。您应该在Servlet中执行业务逻辑(数据库查询和更新,文件上载等),并使用JSP来呈现输出。

答案 1 :(得分:3)

您可以重写代码,使其直接从输入流流式传输到文件。这只需要一个小缓冲区。

答案 2 :(得分:0)

您在内存中创建两次视频: 1. byte dataBytes [] = new byte [formDataLength]; 2. String file = new String(dataBytes);

您可能想要更改...