2017-06-22 86 views
0

我使用Formscanner和新的本地線程其處理一些圖片給它的錯誤後:異常線程「main」 java.lang.OutOfMemoryError:無法創建

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread 
at java.lang.Thread.start0(Native Method) 
at java.lang.Thread.start(Thread.java:717) 
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:950) 
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1357) 
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134) 
at com.albertoborsetta.formscanner.api.FormTemplate.findPoints(FormTemplate.java:852) 
at com.albertoborsetta.formscanner.model.FormScannerModel.analyzeFiles(FormScannerModel.java:562) 
at com.albertoborsetta.formscanner.main.FormScanner.main(FormScanner.java:145) 

該找點方法爲在:

public void findPoints(BufferedImage image, int threshold, int density, 
     int size) throws FormScannerException { 
    height = image.getHeight(); 
    width = image.getWidth(); 
    int cores = Runtime.getRuntime().availableProcessors(); 

    ExecutorService threadPool = Executors.newFixedThreadPool(cores - 1); 
    HashSet<Future<HashMap<String, FormQuestion>>> fieldDetectorThreads = new HashSet<>(); 

    HashMap<String, FormQuestion> templateFields = template.getFields(); 
    ArrayList<String> fieldNames = new ArrayList<>(templateFields.keySet()); 
    Collections.sort(fieldNames); 

    for (String fieldName : fieldNames) { 
     Future<HashMap<String, FormQuestion>> future = threadPool.submit(new FieldDetector(threshold, density, size, this, templateFields.get(fieldName), image)); 
     fieldDetectorThreads.add(future); 
    } 

    for (Future<HashMap<String, FormQuestion>> thread : fieldDetectorThreads) { 
     try { 
      HashMap<String, FormQuestion> threadFields = thread.get(); 
      for (String fieldName : threadFields.keySet()) { 
       FormQuestion field = threadFields.get(fieldName); 
       fields.put(fieldName, field); 
       for (Entry<String, FormPoint> point : field.getPoints().entrySet()) { 
        if (point.getValue() != null) { 
         pointList.add(point.getValue()); 
        } 
       } 
      } 
     } catch (InterruptedException | ExecutionException e) { 
      throw new FormScannerException(e.getCause()); 
     } 
    } 

    threadPool.shutdown(); 

} 

上述函數正在循環中調用,並且java進程的數量增長,並在一個點上引發上述異常。

有什麼辦法可以在調用shutdown方法後殺死這些線程。我不是一個Java開發人員。我做了一些R & D.但我沒有成功。

+0

您正在運行32位或64位JVM嗎?什麼是操作系統使用?內存設置是什麼(Xmx,Xms,Xss ...)? –

+0

池被設想限制運行的線程數,並且你有一個等待每個線程結束的'thread.get'。所以除非你在新線程中調用這個方法(這在stacktrace中是可見的),我不明白這會如何超載。 **但是,當然,它可能是第一個運行的FieldDetector實例,它將所有內存都提供給**。 FieldDetector實例會做什麼? – AxelH

+0

即時通訊使用Ubuntu的64位與openjdk – Baran

回答

2

問題來自於Set<Future>用來保存每個實例以便稍後檢查它們。

在聊天中,你告訴我你正在檢查120.000文件。這意味着有很多未來創建,當池找到一個插槽時,它將創建一個Thread來執行Callable

由於Set持有每個實例,Thread不是垃圾回收,那是什麼讓你泄漏。您需要刪除每個使用的Future以讓GC清除下一個Thread的內存。

使用迭代器而不是環本身很簡單,讓你使用

Iterator<Future<HashMap<String, FormQuestion>>> iterator = fieldDetectorThreads.iterator(); 
while (iterator.hasNext()) { 
    //get the next instance 
    Future<HashMap<String, FormQuestion>> thread = iterator.next(); 
    //Remove it from the set 
    iterator.remove(); 

    //then work on that instance just like before 
    try { 
     HashMap<String, FormQuestion> threadFields = thread.get(); 
     for (String fieldName : threadFields.keySet()) { 
      FormQuestion field = threadFields.get(fieldName); 
      fields.put(fieldName, field); 
      for (Entry<String, FormPoint> point : field.getPoints().entrySet()) { 
       if (point.getValue() != null) { 
        pointList.add(point.getValue()); 
       } 
      } 
     } 
    } catch (InterruptedException | ExecutionException e) { 
     throw new FormScannerException(e.getCause()); 
    } 
} 

該解決方案沒有測試之前刪除當前的實例,但是這應該是能夠釋放內存速度不夠快。

但是,如果提交請求的循環需要很長時間才能結束(在檢查第一個請求之前生成120k未來),那麼在發送每個請求之前,這會中斷。

在這種情況下,可能需要將該邏輯分成兩個線程,一個發送請求,一個檢查結果,直到第一個線程結束並且該集合爲空。


以防萬一,我會在循環之後添加關機請求

threadPool.shutdown(); 

它不應該是必要的,但奇怪的是我的測試程序不無它結束......即使每線程已經被處理,他們似乎保持存在並阻塞主線程。

+0

請幫我解決線程的findCorners方法。 – Baran

+0

我已經恢復了代碼,當我處理了1000張工作表時,它具有相同的效果513進程正在運行,因爲我根據您的建議進行了更改。 – Baran

相關問題