Java堆空间(带有大文件的CMS)

时间:2009-06-16 08:38:35

标签: java memory tomcat

编辑:

获取目录。现在还有另一个问题:

存储中的文件以其DB id作为前缀存储 他们的文件名。当然我不希望用户看到这些。

有没有办法将response.redirect和标题设置结合起来 文件名和大小?

最好的,

     A

你好,

新方法:

是否可以按顺序在tomcat中创建类似IIS的虚拟目录 避免流式传输,只使用标题重定向?我一起玩 背景但却无法实现......

任何想法?

    thx

A

嗨%,

我正面临着Java堆空间的有线问题 把我带到绳索上。

简短版本是:

我编写了一个需要处理的ContentManagementSystem 巨大的文件(> 600mb)也是。 Tomcat堆设置:

-Xmx700m -Xms400m

问题是,上传大文件的确很有效 慢。下载文件会导致java堆空间异常。

尝试下载370mb文件会使tomcat跳转到500mb堆 (应该没问题)并以Java堆空间异常结束。

我不明白,为什么上传工作和下载不? 这是我的下载代码:

byte[] byt = new byte[1024*1024*2];

response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\""); 

FileInputStream fis = null;
OutputStream os = null;

fis = new FileInputStream(new File(filePath));
os = response.getOutputStream();

BufferedInputStream buffRead = new BufferedInputStream(fis);

while((read = buffRead.read(byt))>0)            
{
    os.write(byt,0,read);
    os.flush();
}

buffRead.close();
os.close();

如果我说得对,那么缓冲读者应该照顾好任何一个 记忆问题,对吧?

任何帮助都会受到高度赞赏,因为我没有想法

致以最诚挚的问候,

w ^

9 个答案:

答案 0 :(得分:5)

  

如果我说得对,那么缓冲   读者应该照顾好任何记忆   问题,对吧?

不,这与内存问题无关,因为您已经在使用缓冲区来读取文件,所以实际上没有必要。你的问题在于写作,而不是阅读。

我无法看到您的代码出现任何问题。看起来Tomcat正在缓冲整个响应而不是流式传输。我不确定是什么原因引起的。

response.getBufferSize()返回什么?你应该尝试将response.setContentLength()设置为文件的大小;我依稀记得在某些情况下,一个Web容器会缓冲整个响应以确定内容长度,所以也许这就是正在发生的事情。最好这样做是因为它使客户能够显示下载大小并为下载提供ETA。

答案 1 :(得分:1)

尝试使用ServletResponse的setBufferSizeflushBuffer方法。

答案 2 :(得分:1)

您最好使用 java.nio ,这样您就可以部分阅读资源并释放已经过流的资源!

否则,尽管您已经对JVM环境进行了设置,但最终会出现内存问题。

答案 3 :(得分:1)

我的建议:

Quick-n-easy: 使用更小的阵列!是的,它循环更多,但这不会是一个问题。 5千字节就好了。你会在几分钟内知道这是否适合你。

byte[] byt = new byte[1024*5];

稍微难点: 如果您有权访问sendfile(例如在Tomcat中使用Http11NioProtocol - documentation here),那么请使用它

再努力一点: 将代码切换到Java NIO的FileChannel。我有非常非常相似的代码运行在同样大的文件上,有数百个并发连接和类似的内存设置没有问题。在这些情况下,NIO比普通的旧Java流更快。它使用DMA(Direct Memory Access)的魔力,允许数据从磁盘进入NIC而无需通过RAM或CPU。这是我自己的代码库的代码片段...我已经扯掉了许多来展示基础知识。 FileChannel.transferTo()不保证每个字节发送一次,所以它就在这个循环中。

WritableByteChannel destination = Channels.newChannel(response.getOutputStream());
FileChannel         source      = file.getFileInputStream().getChannel();

while (total < length) {
    long sent = source.transferTo(start + total, length - total, destination);
    total += sent;
}

答案 4 :(得分:1)

以下代码能够将数据流传输到客户端,只分配一个小缓冲区(BUFFER_SIZE,这是一个软点,因为您可能需要调整它):

private static final int OUTPUT_SIZE = 1024 * 1024 * 50; // 50 Mb
private static final int BUFFER_SIZE = 4096;

@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response) 
                     throws ServletException, IOException {
    String fileName = "42.txt";

    // build response headers
    response.setStatus(200);
    response.setContentLength(OUTPUT_SIZE);
    response.setContentType("text/plain");
    response.setHeader("Content-Disposition", 
                        "attachment;filename=\"" + fileName + "\"");
    response.flushBuffer(); // write HTTP headers to the client

    // streaming result
    InputStream fileInputStream = new InputStream() { // fake input stream
        int i = 0;

        @Override
        public int read() throws IOException {
            if (i++ < OUTPUT_SIZE) {
                return 42;
            } else {
                return -1;
            }
        }
    };

    ReadableByteChannel input = Channels.newChannel(fileInputStream);
    WritableByteChannel output = Channels.newChannel(
                                    response.getOutputStream());
    ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);

    while (input.read(buffer) != -1) {
        buffer.flip();
        output.write(buffer);
        buffer.clear();
    }

    input.close();
    output.close();
}

答案 5 :(得分:1)

您是否需要使用Tomcat提供文件?对于这种任务,我们使用了单独的下载机制。我们链接了Apache - &gt; Tomcat - &gt;存储然后添加重写规则以供下载。然后您只需绕过Tomcat,Apache就会将文件提供给客户端(Apache-&gt;存储)。但是,只有在文件存储为文件时才有效。如果从DB或其他类型的非文件存储中读取此解决方案,则无法成功使用。整个方案是您为文件生成下载链接,例如domain / binaries / xyz ...并使用Apache mod_rewrite为域/文件编写重定向规则。

答案 6 :(得分:0)

您是否在应用程序中有任何过滤器,或者您是否使用了tcnative库?您可以尝试使用jvisualvm进行配置文件吗?

编辑:小注释:请注意,如果不清理fileName,则setHeader中存在HTTP响应拆分攻击的可能性。

答案 7 :(得分:0)

为什么不使用tomcat自己的FileServlet?

它肯定会比你想象的更好地发布文件。

答案 8 :(得分:-1)

2 MB的缓冲区方式太大了!一些k应该足够了。兆字节大小的对象是垃圾收集器的真正问题,因为它们通常需要与“普通”对象分开处理(正常==比堆生成小得多)。要优化I / O,您的缓冲区只需要略大于I / O缓冲区大小,即至少与磁盘块或网络包一样大。