2010-11-15 42 views
0

我在我的Grails應用程序上運行了一個很長的批處理。該服務聯繫Web服務並下載本地存儲在grails應用程序(在數據庫中)的xml。 下載的對象非常龐大複雜,應用程序會處理它們並創建本地域對象。 我正在使用Grails 1.2.2,因爲我無法將我的應用程序升級到最新版本(我花了幾個小時,然後扔進了海綿)。在Grails/Tomcat上長時間批量處理OutOfMemoryError

它基本上是一個很長的循環,迭代之間很少有共享信息。

這就像一句:

while(stillObjectsToDo){ 
    def bigObj = myservice.fetchXML 
    def localInstance = myservice.processObj(bigObj) 
    localInstance.saveEverythingToDB 
    clearGORM 
} 

我上運行應用程序的Tomcat,已調整了增加堆大小。 當我處理一個單獨的對象時,我從來沒有遇到過問題。但是,當我運行完整的批次(約1500大對象),我總是得到:

codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException: Executing action [runSampleBatch] of controller [semanticopenstreetmap.EngineController] caused exception: java.lang.OutOfMemoryError: Java heap space 
at java.lang.Thread.run(Thread.java:619) 
Caused by: org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.OutOfMemoryError: Java heap space 
... 1 more 
Caused by: java.lang.OutOfMemoryError: Java heap space 
at java.util.Arrays.copyOf(Arrays.java:2882) 

似乎某種內存泄漏,但我不能找到它。這很奇怪,因爲對象存儲在數據庫中,並且在過程中不再使用,所以應該刷新它們。

我嘗試了以下解決方案,以避免與沒有運氣的問題:在每次迭代

  • 呼叫垃圾收集每隔5-6分鐘沖洗每對象之後

    • 清除Hibernate會話
    • 在循環結束時手動取消先前的對象(可能無用)。

    這一切都沒有奏效。內存使用量不斷增加。 我用虛擬VM和我得到這個圖: http://img12.imageshack.us/img12/5660/memoryleak.png 及其類別: http://img263.imageshack.us/img263/331/memoryleakclasses.png

    我怎樣才能找到並解決此內存泄漏?

    編輯:運行單獨的線程中的每個對象是否有意義?內存泄漏發生在http-0-x進程中,我如何檢查這個對象?

    任何提示?

    謝謝!

    Mulone

  • +0

    您使用的是什麼收集器? – 2010-11-15 09:12:46

    +0

    我使用默認的:Runtime.getRuntime()。totalMemory()和 Runtime.getRuntime()。freeMemory() – Mulone 2010-11-15 11:12:17

    回答

    1

    我會使用Visual VM附加到進程,看看內存正在發生什麼。

    我想知道如果動態生成的代理正在填寫您的燙髮gen空間。 Visual VM將爲您提供證據,證明您是否確實如此。

    +0

    它似乎不是從跟蹤的permgen問題;它似乎是一個「正常」的OOM。 – hvgotcodes 2010-11-15 01:20:59

    +0

    我附上了圖表:http://img12.imageshack.us/img12/5660/memoryleak.png – Mulone 2010-11-15 16:25:33

    1

    您需要將外部分析器附加到您的應用程序。這是一個很好的例子。

    https://visualvm.dev.java.net/

    的基本思想是你的一些選項添加到您的Tomcat啓動腳本,啓動Tomcat和你的分析器,並使用你的應用程序。你會看到實時更新,並能夠看到你的記憶被消耗,釋放,以及什麼。

    你應該看到的是一個圖上升,然後下降,然後上升,然後下降,等等。關鍵是,雖然內存使用量會週期性上升,但基準線隨着時間的推移沒有上升趨勢。所以當圖形下降時,隨着時間的推移它會回落到一些基線。如果在圖表下降後,您看到上升趨勢,則需要確定應用程序的哪個區域正在導致它。 VisualVM有分析堆的方法,所以你可以看到每種類型有多少個對象存在。您應該使用該工具來確定哪些對象未被收集。

    +0

    我使用Visual VM,並且我可以看到堆增長非常緩慢,直到它生成內存不足錯誤。我每5-6分鐘給GC打電話,但似乎沒有解決問題。實際上,如果我從Visual VM(從按鈕)調用GC,它會更好。任何想法? – Mulone 2010-11-15 15:54:14

    +0

    @mulone,更新了我的回答 – hvgotcodes 2010-11-15 16:39:22

    1

    有一個在GORM已知內存泄漏無法通過清除會話固定。 Burt Beckwith已經寫下了它here。基本上,解決辦法是致電DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP.get().clear()

    +0

    謝謝!我已經在clearGORM函數中包含了它,但它似乎不起作用 – Mulone 2010-11-16 10:12:42

    +0

    從您的一個profiler screengrabs中,它似乎是大量的污染堆的char []對象。您的分析器是否允許您查看這些實例的分配位置?也許提取XML的服務緩存響應的地方? – BungleFeet 2010-11-16 17:44:45