java.lang.OutOfMemoryError:

我正在尝试从数据库中检索的字节创建video文件。 该计划在几个小时之前运作良好。 上传大文件后,当我尝试检索它时,它产生错误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) 

请有人告诉我这个错误告诉了什么。 我需要纠正它…….谢谢……

这里,

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

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

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

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

然后使用IOUtils#copy()将其写入所需的输出流(不要忘记在finally中关闭它们!)。

 FileOutputStream output = new FileOutputStream(file); try { IOUtils.copy(videoData, output); } finally { IOUtils.closeQuietly(output); IOUtils.closeQuietly(videoData); } 

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

如果您从像eclipse这样的IDE运行程序,请在运行配置模式下设置配置。

错误说你内存不足。 您需要将更少的内容加载到内存中,或者增加可用的内存总量。

错误告诉:

 OutOfMemoryError: Java heap space 

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

选项-Xmx

示例: -Xmx256m ,最大堆空间为256 MB

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

如果从cli执行,这很容易

java -Xmx2000m youMainJavaFile

如果从eclipse或类似程序执行,则需要进入选项并告诉它在执行JVM时添加此标志。

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中执行此操作,从而提供-Xmx1024m因为VM参数将正常工作。

在IOUtils.write中使用output.flush(),这样缓冲的字节将被写入目标并缓冲区被清除。 内存中没有任何东西。

 StringBuilder sb1 = new StringBuilder(); sb1.append(vid); String videoid=sb1.toString(); 

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

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

另外,了解java堆空间的分配方式和方式:

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

为Java程序设置最小堆为64 MB,最大堆为256 MB HelloWorld:java -Xms64m -Xmx256m HelloWorld如果使用IDE,则必须更改服务器启动中的params。 HTH

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

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

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