@Duplicate - 这不是重复 - 类似的问题专门询问Liferay SendFile方法,它不适用于大文件。以下问题仅涉及将大文件写入Tomcat outpustream。另一个问题没有得到回答,相反,他们告诉他向Liferay提出一个问题,这不是任何问题的答案。下面的代码是Liferay SendFile()方法的代码。将某人引导到Liferay支持不是解决方案。
当我尝试将大文件写入HttpServletResponse getOutputStream()时,我不断得到一个OutOfMemory:Java堆空间错误 - 尽管尝试使用缓冲区,Apache Commons IOUtils.ChunkedOutputStream,以块的形式写出输出 - 没有任何作用。当我使用HttpServletResponse getWriter()方法时也发生了同样的错误并尝试了这种方式..但这里是我的getOutputStream()代码 -
我正在为我的Portlet编写一个下载文件功能,我需要它才能处理非常大的文件 - 但它现在正在努力处理1.4gb文件。
final HttpServletResponse httpResponse = PortalUtil.getHttpServletResponse(response);
// Regular Output Stream
BufferedOutputStream outputStream = new BufferedOutputStream(httpResponse.getOutputStream());
// Also tried using this from Apache Commons, still did not work
//ChunkedOutputStream outputStream = new ChunkedOutputStream(outputStream);
// Desired File Download
InputStream is = new FileInputStream(source_file);
while (remainingLength > 0) {
int readBytes = is.read(bytes, 0, (int)Math.min(remainingLength, bufferSize));
if (readBytes == -1) {
break;
}
// Write it
outputStream.write(bytes, 0, readBytes);
// Other Attempts - none of these worked
//IOUtils.writeChunked(bytes, outputStream); //This does not work
//IOUtils.write(bytes, outputStream); // Neither does this
remainingLength -= readBytes;
// Attempted to flush after every 1mb written - but it does not fix the issue
if(buffer >= bufferSize) {
outputStream.flush();
buffer = 0;
} else {
buffer += readBytes;
}
}
// ALTERNATIVELY - We also tried using Apache IOUtils.copy() and copyLarge()
IOUtils.copyLarge(is, outputStream);
//IOUtils.copy(is, outputStream);
// This is in a finally {} block, try{} encloses the above code
IOUtils.closeQuietly(is, outputStream);
outofmemory异常发生在outputStream.write()行上 - 我无法弄清楚如何正确地将文件写入输出流,而不会导致抛出该异常。它适用于较小的200mb文件,但从不适用于较大的文件。
我对Tomcat的启动参数是-Xmx2048m -XX:MaxPermSize = 2048m -Xms2048m
另请注意:我在循环结束时添加了一个日志来写入总写入字节,并将其转换为MB。它达到512mb。
更新的堆栈跟踪 - 我重新启动了服务器并获得了更好的服务器。
错误发生在outputStream.write()上 - 如果你深入到堆栈跟踪中,抛出错误的实际行是在行上的UnsyncByteArrayOutputStream.java:91中
byte[] newBuffer = new byte[newBufferSize];
SEVERE:servlet文件管理器Servlet.service()抛出异常 java.lang.OutOfMemoryError:Java堆空间 at com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream.write(UnsyncByteArrayOutputStream.java:91) at com.liferay.portal.kernel.servlet.ServletOutputStreamAdapter.write(ServletOutputStreamAdapter.java:54) 在java.io.BufferedOutputStream.write(BufferedOutputStream.java:122) 在com.healthmap.FileManager.download(FileManager.java:370) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.liferay.portal.kernel.portlet.LiferayPortlet.callActionMethod(LiferayPortlet.java:163) at com.liferay.util.bridges.mvc.MVCPortlet.callActionMethod(MVCPortlet.java:249) 在com.liferay.portal.kernel.portlet.LiferayPortlet.processAction(LiferayPortlet.java:90) at com.liferay.util.bridges.mvc.MVCPortlet.processAction(MVCPortlet.java:212) 在com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:71) at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:48) 在com.liferay.portal.kernel.servlet.PortletServlet.service(PortletServlet.java:112) 在javax.servlet.http.HttpServlet.service(HttpServlet.java:731) 在org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) 在org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116) 在com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilter.doFilter(InvokerFilter.java:119) 在org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748) at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:604) 在org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:543) 在com.liferay.portlet.InvokerPortletImpl.invoke(InvokerPortletImpl.java:583) 在com.liferay.portlet.InvokerPortletImpl.invokeAction(InvokerPortletImpl.java:628) at com.liferay.portlet.InvokerPortletImpl.processAction(InvokerPortletImpl.java:308) at com.liferay.portlet.PortletContainerImpl._doProcessAction(PortletContainerImpl.java:389) 在com.liferay.portlet.PortletContainerImpl.processAction(PortletContainerImpl.java:107) at com.liferay.portlet.SecurityPortletContainerWrapper.processAction(SecurityPortletContainerWrapper.java:109) at com.liferay.portlet.RestrictPortletContainerWrapper.processAction(RestrictPortletContainerWrapper.java:75)