2017-02-24 74 views
0

我在下面的代碼中做錯了什麼?或者netty4組件存在一些已知的問題,它只是有很高的內存使用率?Apache Camel Netty4高內存使用率

我的問題:

我使用駱駝的netty4組件從一個套接字流數據,彙總,然後把它的道路上。

我已經嘗試了很多不同的策略來聚合數據,沒有任何東西似乎幫助或傷害了內存使用。

我有30秒的聚合時間段,並且在那30秒內數據總計大約1.3MB。

但是,我注意到我的內存使用量每隔30秒增加4MB。我在Linux中使用watch free -m來監視內存消耗。除了運行Camel進程的終端之外,沒有其他進程在前臺運行。內存使用情況在運行Camel進程之前是完全穩定的(MB的規模沒有波動)。

我已經玩過幾乎所有由Camel文檔提供的netty4設置,這對我來說很明顯,沒有什麼東西似乎減少了正在使用的內存量。

我從使用命令行運行駱駝實例

java -Xms200M -Xmx275M -Xss512k -Drolling_log_dir=/logs/ -jar myCamel.jar 

我的路線:

from(netty4:tcp://localhost:12345?clientMode=true&textline=true).routeId(routeId + "A") 
    .log(LoggingLevel.INFO, rollingLogFile, "${body}") 
    .aggregate(constant(true), new StringAggregationStrategy(dataType)) 
    .completionInterval(30000) 
    .to(fileUri); 

from(fileUri).routeId(routeId + "B") 
    .process(doTheThing) 
    .to(pushFile) 
    .log("Transferred ${file:name} complete"); 

StringAggregationStrategy.java:

package com.aggregators; 

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.IOException; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.nio.file.StandardOpenOption; 

import org.apache.camel.Exchange; 
import org.apache.camel.processor.aggregate.AggregationStrategy; 

public class StringAggregationStrategy implements AggregationStrategy { 
    private static Path tempFileDir; 
    public StringAggregationStrategy(String dataType){ 
     tempFileDir = Paths.get("camelTempAggFileStorage/" + dataType + "/"); 
    } 

    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) { 
     String newBody = newExchange.getIn().getBody(String.class); 
     String exchangeId; 
     Path tempAggFilePath; 

     if (!Files.exists(tempFileDir)){ 
      try { 
       Files.createDirectories(tempFileDir); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 

     if (oldExchange == null){ 
      cleanDirectory(tempFileDir); 
      exchangeId = newExchange.getExchangeId(); 
      tempAggFilePath = Paths.get(tempFileDir.toString() + "/" + exchangeId + ".txt"); 
     } else{ 
      File oldFile = oldExchange.getIn().getBody(File.class); 
      tempAggFilePath = oldFile.toPath(); 
     } 

     try (BufferedWriter writer = Files.newBufferedWriter(tempAggFilePath, StandardOpenOption.APPEND, StandardOpenOption.CREATE)){ 
      if (oldExchange == null) { 
       writer.write(newBody); 
       newExchange.getIn().setBody(tempAggFilePath.toFile()); 
       return newExchange; 
      } else { 
       writer.newLine(); 
       writer.write(newBody); 
       oldExchange.getIn().setBody(tempAggFilePath.toFile()); 

       return oldExchange; 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return oldExchange; 

    } 

    private void cleanDirectory(Path tempFileDir) { 
     for (File tempFile: tempFileDir.toFile().listFiles()){ 
      if (!tempFile.isDirectory()){ 
       tempFile.delete(); 
      } 
     } 
    } 

} 

編輯:使用的VisualVM和監控這似乎是應用程序的繼續當發生Broken Pipe異常等情況時,Netty開始產生額外的線程,但這些線程永遠不會被清理。在我的Java程序運行17個小時後,當看到我的堆轉儲時,我看到最大的違規者(該類實例的數量)分別是io.netty.util.Recycler$DefaultHandleio.netty.channel.ChannelOutboundBuffer$Entry,分別爲20.2%(59,630)和19.8%(58,306)分別在我的堆裏。

有關駱駝如何減輕這些設置的任何想法?

+0

「我的記憶體使用量每30秒增加4MB。」 - 測量如何? – slim

+0

啊對不起,我解釋了一切,但.. ..哈哈。除了使用Java進程的終端之外,我已經關閉了所有的東西,我正在看Linux中的'free -m'命令。在我運行該進程之前,內存處於穩定狀態,所以我不知道其他任何內容都在同時使用內存。我應該更新問題 – Jsmith

+0

磁盤上的1.3MB可能會導致4MB的內存因爲壓縮而被加載到內存中。因此,每隔30秒將傳入的數據聚合到一個文件中,然後該文件將保存在內存中。內存增加的原因可能是該文件在處理完成時未從內存中刪除,或者GC只是在需要時才啓動。如果您只是將傳入數據附加到交換機構而不是創建文件,會發生什麼情況? – noMad17

回答

2

Java將聲稱儘可能多的內存,因爲它喜歡,達到配置的限制。

即使GC清除掉只有在快滿時纔會執行的對象,它通常也不會將它聲明的內存返回給操作系統。它會保留它爲未來對象而設的malloc()d。

因此,你會期望幾乎所有的Java程序都會創建大量的新對象(即使它們是短命的),以保持內存的聲明直到它的堆達到-Xmx指定的大小。

熱點做自己的內存管理 - 也就是說,它malloc()的大塊,並用它們按照自己的意願,而不是做在每次創建對象的時間malloc()

因此free不是查看Java程序本身是否行爲的好工具。

要查看JVM內存的內部,請使用VisualVM等工具 - 然後您可以觀察堆大小,對象數等等。如果程序真的在泄漏內存,您會在這裏看到它。

如果您希望Java程序使用較少的內存,請將其設置爲較低,這將強制GC在較小的內存分配中工作。