2017-02-24 48 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在较小的内存分配中工作。