Java JVM/Tomcat在并行上传过多时崩溃(堆空间)?

Java JVM/Tomcat在并行上传过多时崩溃(堆空间)?,java,spring,servlets,grails,jvm,Java,Spring,Servlets,Grails,Jvm,我有一个在Tomcat7上运行的Servlet应用程序。我在setenv.sh中设置了以下内容 CATALINA_OPTS=" -server -Xms1G -Xmx5G -XX:MaxPermSize=512m -Dfile.encoding=UTF-8"; 服务器运行在Ubuntu12.04LTS上,有6个内核和8GB内存。 我的应用程序是一个Grails/Spring/Java应用程序,用户可以在其中上传图像。有时,3-5个用户同时开始上传图像。在这些情况下,由于以下错误,我的Tom

我有一个在Tomcat7上运行的Servlet应用程序。我在setenv.sh中设置了以下内容

CATALINA_OPTS="
-server 
-Xms1G 
-Xmx5G
-XX:MaxPermSize=512m
-Dfile.encoding=UTF-8";
服务器运行在Ubuntu12.04LTS上,有6个内核和8GB内存。 我的应用程序是一个Grails/Spring/Java应用程序,用户可以在其中上传图像。有时,3-5个用户同时开始上传图像。在这些情况下,由于以下错误,我的Tomcat崩溃:

java.lang.OutOfMemoryError: Java heap space
我知道我必须增加Tomcat的Xmx参数来防止这个问题。但说真的,我的情况到底出了什么问题

  • 在我的场景中,是否有处理文件上传的最佳实践

  • 我怎样才能预防这个问题?我的意思是,当5GB不足以进行3-5次并行上传时,数百次并行上传需要多少资源

  • 我的应用程序是如此糟糕还是文件上传占用了如此多的资源是正常的

  • 注意:用户上传的文件大小为2-8MB

    以下是我在视图中进行上传的方式:

       <g:form method="post" action="save" enctype="multipart/form-data">
        <input type="file" name="file"/>
        <input type="submit"/>
       </g:form>
    
    在config/spring/resource.groovy中,我执行了以下操作:

    beans = { 
      multipartResolver(org.springframework.web.multipart.commons.CommonsMultipartResolver){
    
            // Max in memory 100kbytes
            maxInMemorySize=102400
    
        }
    
    } 
    

    上传的文件是图像。它们将被缩放并保存到磁盘

    图像将保存为:

    bytes [] currentImage = // some image in bytes ...
    def newFile = new FileOutputStream(fullPath)
    newFile.write(currentImage)
    newFile.close()
    
    避免,改为使用以避免将整个文件内容读入内存

    因此,请将代码更改为:

    def file = request.getFile('image')
    InputStream inputStream = file.inputStream
    

    您没有提到如何处理上传的文件,但是如果您想最大限度地减少堆的使用,请确保在应用程序的所有层中都通过
    InputStream
    ,并且不要转换为
    字节[]

    文件有多大?尝试使用jvisualvm查看是什么占用了所有内存。在上载过程中,您的应用程序是否将整个文件内容保存在内存中?可以对文件上传进行流式处理,commons fileupload支持这一点:@samlewis如何使用Grails完成文件上传流式处理?你能给出一个答案吗?5GB的堆,3-5个用户上传2-8MB的文件应该不会有问题,即使你没有流媒体。也许您应该遵循@BevynQ关于使用JVisualVM进行评测的建议。如果你想对GRAILS应用程序提出改进建议,请考虑用文件上传代码更新问题。@ SAMLWWI用我的代码更新我的问题来上传。你知道我是如何让流媒体工作的吗?你能告诉我应该如何根据你的建议修改代码以获得文件的字节数吗?上传的文件是图像。它们将被缩放并保存到磁盘。我更新了我的答案。如何将映像作为inputStream保存到磁盘?为什么bytes[]不好?缩放可能需要将图像读取到内存中,因此流式传输可能不是您的选择。我将回到@BevynQ关于使用JVisualVM进行评测的建议。字节[]是坏的,因为它是内存中的整个文件内容,但对您来说,这可能是不可避免的。因此,除了分析外,在我必须缩放图像时,您建议如何减少内存使用?有没有什么方法可以在缩放后快速释放内存?图像处理会占用大量的if内存,因此您可以尝试进行优化。您可以限制同时缩放的图像数量,例如使用ThreadPoolExecutor。就我个人而言,我会要求用户上传正确大小的图像,并使用ImageIO验证grails应用程序中的宽度和高度。
    def file = request.getFile('image')
    InputStream inputStream = file.inputStream