2010-02-25 141 views
2

我在跟蹤中描述了以下錯誤,當我嘗試上傳一個80,193KB FITS文件進行處理時,爲了顯示選擇的字段。基本上我有一個模擬web界面,允許用戶選擇最多6個FITS文件進行上傳和處理。當我上傳兩個[不同的] FITS文件(每個大約54,574KB)時,我不會收到錯誤。這些字段在控制檯上顯示/打印。然而,在上傳單個80,193KB文件時,我得到下面的錯誤。我如何解決它?java.lang.OutOfMemoryError:Java堆空間

我最初以爲迭代當時正在計算昂貴的,但我懷疑它occcurs上調用readHDU爲80MB的文件:

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(); 
      } 
     }  
    } 
+4

您是否嘗試過使用'-Xmx'開關增加虛擬機可用的堆大小? – 2010-02-25 19:06:10

+2

您使用的API是否支持迭代器樣式訪問?也就是說,Java不需要讀取整個文件來處理它,只需要記錄一次。如果這不是你正在做的選擇,你需要遵循Greg的建議並增加堆大小。 – Mike 2010-02-25 19:11:20

+0

不,我還沒有 – Terman 2010-02-25 19:13:25

回答

5

聽起來像是你還沒有分配足夠的內存來Tomcat的 - 你可以解決這個問題例如指定-Xmx512m以分配高達512Mb的內存。

請參閱here瞭解有關如何設置的更多詳細信息。

2

你正在嘗試使用比你有更多的RAM。

嘗試通過在啓動程序時添加-Xmx標誌來增加最大內存。

java -Xmx128m youProgram 

這將分配128 MB內存作爲最大到您的程序。

+0

「這將爲您的程序分配128 MB的內存」 - 不完全 - 這將設置JVM用於堆的最大* *大小爲128m。除非另有說明(使用-Xms),堆的*開始*大小仍然是默認值。 – 2010-02-25 19:17:13

+0

應該指出的是,系統將使用大量的內存而不是非堆內存。通常,我在指定的堆大小上看到30-40 MB。 – 2010-02-25 19:30:13

+0

奧斯卡 - 通常是的,但在這種情況下,海報使用應用服務器(Tomcat),所以「正常」java -X路線可能沒有那麼有用 – Brian 2010-02-26 10:17:07

0

java.lang.OutOfMemoryError表示您已經超出了JVM分配的內存。使用-Xmx更改JVM的最大內存堆大小。 (謝謝軟件猴)

您可以將此看什麼是JVM內存大小:

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

不正確 - 使用'-Xmx'來更改最大堆大小。 -Xms更改初始堆大小。 – 2010-02-25 19:32:38

3

最佳的解決將是如此,它不會不必要複製的提升代碼內存中的數據。堆棧跟蹤表明代碼試圖克隆內存中的文件內容。如果不可能增強(第三方?)代碼,以便它不這樣做,而是立即處理它,然而配置/使用commons FileUpload,以便它不保留上載的文件在內存中,但而不是在本地磁盤文件系統的臨時存儲中。

你最好儘量減少使用的內存然後將使用DiskFileItemFactory與一個小門檻(默認10KB的方式,這是負擔得起的)。

ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); 

這樣你就有足夠的內存用於真正的處理。

如果你仍然遇到堆內存限制,那麼下一步確實會增加堆。

15

大多數的答案都是圍繞增加你的堆的大小從默認值(這是64MB)。 64MB可以解釋爲什麼你能夠成功上傳54,574KB,因爲它的尺寸小於這個尺寸,我敢打賭,tomcat和你的程序在啓動時不會佔用超過10MB的空間。增加記憶力是一個好主意,但它確實是治療症狀而非疾病。

如果您打算允許多個用戶上傳大文件,那麼兩個用戶同時上傳80MB文件需要160MB。而且,如果3個用戶這樣做,你將需要240MB等,這是我的建議。在將它寫入磁盤之前,找一個不會將這些東西讀入RAM的庫。這將使您的應用程序規模擴大,這是解決此問題的真正解決方案。

使用jconsole(附帶JDK)在程序運行時查看您的堆大小。 Jconsole非常易於使用,您無需配置JVM即可使用它。所以在這個意義上說它比探查器容易得多,但是你不會獲得關於你的程序的更多細節。然而,你可以更好地看到記憶的三部分(伊甸園,倖存者和終身)。即使已經爲JVM分配了大量內存,有時奇怪的事情也會導致其中一個區域內存不足。 JConsole會告訴你這樣的事情。

相關問題