java.lang.OutOfMemoryError:
Posted
技术标签:
【中文标题】java.lang.OutOfMemoryError:【英文标题】:java.lang.OutOfMemoryError: 【发布时间】:2013-02-05 22:46:41 【问题描述】:我正在尝试根据从数据库中检索到的字节创建视频文件。该程序在几个小时前运行良好。上传大文件后,当我尝试检索它时,它会产生错误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)
请任何人告诉我这个错误说明了什么。我需要纠正的地方......谢谢......
【问题讨论】:
【参考方案1】:这里,
byte[] videoData = rs.getBytes("videofull");
您将整个文件内容存储在服务器的内存中。你知道,byte[]
的一个字节占用了 Java 内存的一个字节。如果你有例如只有 500MB 内存并且文件超过 500MB,那么你会得到这个错误。请注意,当 10 个用户同时请求 50MB 的视频文件时,您也会得到它。因此,按照其他答案的建议增加 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);
【讨论】:
@BalusC 谢谢......这个问题的完美答案......我在增加内存后也遇到了错误。但现在它运作良好......非常感谢......【参考方案2】: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,则必须在服务器启动时更改参数。 高温
【讨论】:
【参考方案3】:在 IOUtils.write 内部使用 output.flush(),这样缓冲的字节将被写入目标并且缓冲区被清除。什么都不会留在记忆中。
【讨论】:
【参考方案4】:由于您的视频文件很大,它已经完成了堆中的所有内存。您必须通过将 VM 参数设置为 -Xmx1024m 来增加堆大小。这会将您的堆空间增加到 1 GB。如果问题仍然存在,那么您必须使用 java vm visual 来分析程序的哪个部分正在消耗更多内存,并且您应该寻找其他方法来减少它。将堆空间增加到 1 GB 以上并不是解决堆空间问题的好方法。
如果您从 Eclipse 之类的 IDE 运行程序,请将您的配置设置为作为配置模式运行。
【讨论】:
【参考方案5】: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 参数将正常工作。
【讨论】:
【参考方案6】:使用 -Xmx 标志来增加分配给 JVM 的堆空间。 -以Xmx1500m为例。
如果从 cli 执行,这很容易
java -Xmx2000m youMainJavaFile
如果你是从 eclipse 等执行,你需要进入选项并告诉它在执行 JVM 时添加这个标志。
【讨论】:
我不认为你可以......如果允许代码改变自己的操作参数,那将是安全违规...... 这是一个临时解决方案。 正如@BalusC 所指出的,这只是一个临时解决方案,因为更大的文件会导致同样的问题。真正的解决方案是使用输入流而不是使用 File / byte[] 对象【参考方案7】:错误告诉我们:
OutOfMemoryError: Java heap space
您需要更多堆空间:您可以配置 VM 以使用更多堆空间。
选项-Xmx
示例:-Xmx256m
用于 256 MB 的最大堆空间
【讨论】:
没有人可以以编程方式更改堆空间!你必须在启动 java 虚拟机时指定堆的最大大小,或者告诉同事如果他们启动了 VM。【参考方案8】:您的堆太小无法容纳您的应用程序分配的所有对象。
最简单的解决方案是增加堆大小。例如。 -Xms1g -Xmx1g
或者,您可以尝试分析应用程序以查看内存分配来自何处并优化该代码路径。
【讨论】:
【参考方案9】:错误提示您内存不足。您需要将更少的内容加载到内存中,或者增加可用内存的总量。
【讨论】:
以上是关于java.lang.OutOfMemoryError:的主要内容,如果未能解决你的问题,请参考以下文章