java.lang.OutOfMemoryError:Java 堆空间

问题描述 投票:0回答:6

当我尝试上传 80,193KB 的 FITS 文件进行处理以显示选择字段时,跟踪中出现如下所述的错误。基本上我有一个模拟 Web 界面,允许用户选择最多 6 个 FITS 文件进行上传和处理。当我一次上传两个[不同的] FITS 文件(每个文件大约 54,574KB)进行处理时,我没有收到错误。这些字段显示/打印在控制台上。但是,在上传单个 80,193KB 文件时,我收到以下错误。我该如何解决?

我最初认为迭代的计算成本很高,但我怀疑它是在调用 80MB 文件的 readHDU 时发生的:

while ((newBasicHDU = newFits.readHDU()) != null) { 

如何有效解决?我正在 Windows 7 上运行该程序。干杯

踪迹:

SEVERE: Servlet.service() for servlet FitsFileProcessorServlet threw exception
java.lang.OutOfMemoryError: Java heap space
    at java.lang.reflect.Array.multiNewArray(Native Method)
    at java.lang.reflect.Array.newInstance(Unknown Source)
    at nom.tam.util.ArrayFuncs.newInstance(ArrayFuncs.java:1028)
    at nom.tam.fits.ImageData.read(ImageData.java:258)
    at nom.tam.fits.Fits.readHDU(Fits.java:573)
    at controller.FITSFileProcessor.processFITSFile(FITSFileProcessor.java:79)
    at controller.FITSFileProcessor.doPost(FITSFileProcessor.java:53)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
    at java.lang.Thread.run(Unknown Source)

代码:

/**
     * 
     * @param
     * @return
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // Check that we have a file upload request
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);

        if (isMultipart) {

            Fits newFits = new Fits();
            BasicHDU newBasicHDU = null;
            ServletFileUpload upload = new ServletFileUpload();                     // Create a new file upload handler

            // Parse the request
            try {
                //List items = upload.parseRequest(request);                        // FileItem
                FileItemIterator iter = upload.getItemIterator(request);

                // iterate through the number of FITS FILES on the Server
                while (iter.hasNext()) {
                    FileItemStream item = (FileItemStream) iter.next();
                    if (!item.isFormField()) {
                        this.processFITSFile(item, newFits,newBasicHDU );
                    }
                }
            } catch (FileUploadException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }       
        }
    }

    /**
     * 
     * @param
     * @return
     */
    public void processFITSFile(FileItemStream item, Fits newFits, BasicHDU newBasicHDU) throws IOException {

        // Process the fits file
        if (!item.isFormField()) {
            String fileName = item.getName();                                       //name of the FITS File
            try {   
                System.out.println("Fits File Fields Printout: " +  fileName);
                InputStream fitsStream = item.openStream();                             
                newFits = new Fits(fitsStream);
                System.out.println( "number of hdu's if: " + newFits.getNumberOfHDUs());

                while ((newBasicHDU = newFits.readHDU()) != null)  {                //line 76
                    System.out.println("Telescope Used: " + newBasicHDU.getTelescope());
                    System.out.println("Author: " + newBasicHDU.getAuthor());
                    System.out.println("Observer: " + newBasicHDU.getObserver() );
                    System.out.println("Origin: " + newBasicHDU.getOrigin() );
                    System.out.println("End of Printout for: \n" + fileName);
                    System.out.println();               
                }

                fitsStream.close();

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }       
    }
java servlets
6个回答
16
投票

大多数答案都集中在增加默认值(64MB)的堆大小。 64MB 可以解释为什么你能够成功上传 54,574KB,因为它低于这个大小,而且我敢打赌 tomcat 和你的程序在启动时占用的空间不会超过 10MB。增加记忆力是个好主意,但它实际上是治标不治本。

如果您计划允许多个用户上传大文件,那么两个用户同时上传 80MB 文件将需要 160MB。而且,如果 3 个用户执行此操作,您将需要 240MB 等。这是我的建议。找到一个在将这些内容写入磁盘之前不会将其读入 RAM 的库。这将使您的应用程序扩展,这才是这个问题的真正解决方案。

程序运行时使用jconsole(JDK自带)查看堆大小。 Jconsole 确实易于使用,您无需配置 JVM 即可使用它。因此,从这个意义上说,它比分析器容易得多,但您不会获得有关程序的更多详细信息。但是,您可以更好地看到内存的三个部分(Eden、Survivor 和 Tenured)。有时奇怪的事情可能会导致这些区域之一耗尽内存,即使您已经为 JVM 分配了大量内存。 JConsole 会向您展示类似的内容。


5
投票

听起来您没有为 Tomcat 分配足够的内存 - 您可以通过指定 -Xmx512m 来解决此问题,例如分配最多 512Mb 的内存。

有关如何设置的更多详细信息,请参阅此处


3
投票

最好的解决办法是增强代码,这样它就不会不必要地重复内存中的数据。堆栈跟踪表明代码正在尝试克隆内存中的文件内容。如果无法增强(第 3 方?)代码以使其不执行此操作,而是“立即”处理它,则应配置/使用 commons FileUpload,以便它不会将上传的文件保留在内存中,但而不是在本地磁盘文件系统的临时存储中。 您最好的尝试是尽量减少使用的内存,然后使用带有一点阈值的

DiskFileItemFactory

(顺便说一下,默认为10KB,这是可以承受的)。
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());

这样你就有足够的内存来进行真正的处理。

如果仍然达到堆内存限制,那么下一步确实是增加堆。


2
投票

尝试在启动程序时添加

-Xmx

标志来增加最大内存。


java -Xmx128m youProgram

这将为您的程序分配 128 MB 内存作为“最大值”。 

java.lang.OutOfMemoryError 意味着您已经超出了 JVM 分配的内存。使用 -Xmx 更改 JVM 的最大内存堆大小。 (谢谢软件猴)


1
投票

MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); System.out.println( memoryBean.getHeapMemoryUsage() );

首先,可以从 Java 程序中打印当前最大堆大小:

0
投票

检查当前的最大HeapSize(以MB为单位)后,如何设置它: 配置 JVM 选项:

在您的程序或环境的 JVM 选项中。
添加 -Xmx 选项来设置最大堆大小。
例如,-Xmx10240m 将最大堆大小设置为 10240 MB。

© www.soinside.com 2019 - 2024. All rights reserved.