3

我正在尝试从从数据库中检索到的字节创建视频文件。该程序在几个小时前运行良好。上传大文件后,当我尝试检索它时,它正在产生错误java.lang.OutOfMemoryError:

我的代码是:

    conn = prepareConnection();
    StringBuilder sb=new StringBuilder(1024);
    sb.append("select videoname,videoid,videofull from ").append(uname.trim()).append("video");
    String sql=sb.toString();

    stmt = conn.prepareStatement(sql);
    ResultSet rs = stmt.executeQuery();

    while(rs.next()){
         byte[] videoData = rs.getBytes("videofull");       //#57
         int vid=rs.getInt("videoid");
         StringBuilder sb1 = new StringBuilder();
         sb1.append(vid);
         String videoid=sb1.toString();
         String vname=rs.getString("videoname");
         File file=new File("C:/Users/JamesPJ/Documents/skypark/skypark/WebContent/sp/resources/videos/"+vname+""+videoid+".mp4");

        if(file.exists() && !file.isDirectory()){
            continue;
        }
        else
        {
         FileOutputStream output = new FileOutputStream(file);
         IOUtils.write(videoData, output);
         output.close();
        }
       }
    request.setAttribute("uname", uname);
    RequestDispatcher dispatcher = request.getRequestDispatcher("/VideoList");
    if(dispatcher != null) {
        dispatcher.forward(request, response);
    } 

控制台输出为:

Exception in thread "http-bio-8080-exec-3" java.lang.OutOfMemoryError: Java heap space
at oracle.sql.BLOB.getBytes(BLOB.java:217)
at oracle.jdbc.driver.T4CBlobAccessor.getBytes(T4CBlobAccessor.java:462)
at oracle.jdbc.driver.OracleResultSetImpl.getBytes(OracleResultSetImpl.java:716)
at oracle.jdbc.driver.OracleResultSet.getBytes(OracleResultSet.java:402)
at skypark.VideoFileCreator.doGet(VideoFileCreator.java:57)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:412)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
at skypark.VideoStream.processRequest(VideoStream.java:48)
at skypark.VideoStream.doGet(VideoStream.java:64)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:931)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

请任何人告诉我这个错误告诉我什么。我需要纠正的内容......谢谢......

4

9 回答 9

11

这里,

byte[] videoData = rs.getBytes("videofull");

您将整个文件内容存储在服务器的内存中。你知道,一个字节的 abyte[]吃掉了 Java 的一个字节的内存。例如,如果您只有 500MB 内存并且文件超过 500MB,那么您将得到这个错误。请注意,当 10 个用户同时请求 50MB 的视频文件时,您也会得到它。因此,按照其他答案的建议增加 Java 内存只是一个临时解决方案,并没有经过深思熟虑。

您需要以类似的方式获取它,InputStream以便在内部仅分配几个(千)字节作为内存中的流式缓冲区,而不是整个文件内容。

InputStream videoData = rs.getBinaryStream("videofull");

并将其写入所需的输出流,IOUtils#copy()而不是使用(不要忘记在最后关闭它们!)。

FileOutputStream output = new FileOutputStream(file);
try {
    IOUtils.copy(videoData, output);
} finally {
    IOUtils.closeQuietly(output);
    IOUtils.closeQuietly(videoData);
}
于 2013-02-20T20:23:21.963 回答
2

由于视频文件的大小很大,它已经完成了堆中的所有内存。您必须通过将 VM 参数设置为 -Xmx1024m 来增加堆大小。这会将您的堆空间增加到 1 GB。如果问题仍然存在,那么您必须使用 java vm visual 来分析程序的哪个部分消耗更多内存,并且您应该采用其他方法来减少它。将堆空间增加到 1 GB 以上并不是解决堆空间问题的好方法。

如果您从 Eclipse 之类的 IDE 运行程序,请将您的配置设置为作为配置模式运行。

于 2013-02-20T19:37:26.100 回答
1

该错误表明您内存不足。您需要将更少的东西加载到内存中,或者增加可用的内存总量。

于 2013-02-20T19:25:24.647 回答
1

错误告诉:

OutOfMemoryError: Java heap space

您需要更多堆空间:您可以配置 VM 以使用更多堆空间。

选项 -Xmx

示例: -Xmx256m 对于 256 MB 的最大堆空间

于 2013-02-20T19:26:18.200 回答
1

使用 -Xmx 标志来增加分配给 JVM 的堆空间。-Xmx1500m 例如。

如果从 cli 执行,这很容易

java -Xmx2000m youMainJavaFile

如果您是从 eclipse 等执行,则需要进入选项并告诉它在执行 JVM 时添加此标志。

于 2013-02-20T19:27:50.070 回答
1

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

Oracle 文档说,这意味着您应该增加运行程序的 JVM 的内存限制。增加堆大小:

JVM_ARGS="-Xmx1024m"

这会将堆大小设置为 1024mb。或者您可以在您的 IDE 中执行此操作,在运行配置中提供-Xmx1024mVM 参数将正常工作。

于 2013-02-20T19:29:09.457 回答
1

在 IOUtils.write 内部使用 output.flush(),这样缓冲的字节将被写入目标并且缓冲区被清除。没有什么会留在记忆中。

于 2013-02-20T20:00:55.060 回答
1
StringBuilder sb1 = new StringBuilder();
     sb1.append(vid);
     String videoid=sb1.toString();

这是一种方法,这是另一种方法:

     String videoId = new String(new Integer(rs.getInt("videoid")));

此外,了解什么/如何分配 java 堆空间:

    -Xms<size>        set initial Java heap size
    -Xmx<size>        set maximum Java heap size
    -Xss<size>        set java thread stack size

要将 Java 程序 HelloWorld 的最小堆设置为 64 MB,最大堆设置为 256 MB: java -Xms64m -Xmx256m HelloWorld 如果您使用的是 IDE,则必须在服务器启动时更改参数。高温高压

于 2013-02-20T20:01:12.990 回答
0

您的堆太小,无法容纳应用程序分配的所有对象。

最简单的解决方案是增加堆大小。例如-Xms1g -Xmx1g

或者,您可以尝试分析应用程序以查看内存分配来自何处并优化该代码路径。

于 2013-02-20T19:25:45.133 回答