写入getOutputStream()的Tomcat HttpServletResponse总是导致大文件下载的OutOfMemory错误

时间:2017-05-30 18:10:36

标签: java tomcat liferay

@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)

0 个答案:

没有答案