我正在尝试从数据库中检索的字节创建视频文件。该计划在几个小时之前运作良好。上传大文件后,当我尝试检索它时,它产生错误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)
请有人告诉我这个错误告诉了什么。我需要纠正的内容.......谢谢......
答案 0 :(得分:11)
下面,
byte[] videoData = rs.getBytes("videofull");
您将整个文件内容存储在服务器的内存中。你知道,byte[]
的一个字节占用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);
}
答案 1 :(得分:2)
由于视频文件的大小很大,它已经完成了堆中的所有内存。您必须通过将VM参数设置为-Xmx1024m来增加堆大小。这会将堆空间增加到1 GB。如果问题仍然存在,那么你必须使用java vm visual来分析你的程序的哪个部分正在消耗更多的内存,并且你可以通过其他方式来减少它。增加堆空间大于1 gb并不是解决堆空间问题的好方法。
如果从像eclipse这样的IDE运行程序,请在运行配置模式中设置配置。
答案 2 :(得分:1)
错误表明你内存不足。您需要将更少的内容加载到内存中,或者增加可用内存的总量。
答案 3 :(得分:1)
错误告诉:
OutOfMemoryError: Java heap space
您需要更多堆空间:您可以将VM配置为使用更多堆空间。
选项-Xmx
示例:-Xmx256m
表示256 MB的最大堆空间
答案 4 :(得分:1)
使用-Xmx标志来增加分配给JVM的堆空间。例如-Xmx1500m。
如果从cli执行,这很容易
java -Xmx2000m youMainJavaFile
如果从eclipse或类似程序执行,则需要进入选项并告诉它在执行JVM时添加此标志。
答案 5 :(得分: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中执行此操作,从而提供-Xmx1024m
,因为VM参数将正常工作。
答案 6 :(得分:1)
在IOUtils.write内部使用output.flush(),以便将缓冲的字节写入目标并清除缓冲区。没有什么能留在记忆中。
答案 7 :(得分: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,则必须更改服务器启动中的参数。 HTH
答案 8 :(得分:0)
堆太小,无法保存应用程序分配的所有对象。
最简单的解决方案是增加堆大小。例如。 -Xms1g -Xmx1g
或者,您可以尝试分析应用程序以查看来自内存分配的位置并优化该代码路径。