运行下面的代码会导致Java堆空间异常。
来自.NET并掌握GC的工作原理我想知道在尝试运行以下内容时,在内存管理方面是否需要考虑一些事项:
public static void main(String[] args) throws NumberFormatException, ParseException, IOException {
Jedis jedis = new Jedis("<HostName>");
TimeSeriesPoints retrieved = null;
while(!finished) {
try {
finished = true;
List<String> keys = getNextFiftyKeys();
String[] cacheKeys = new String[keys.size()];
List<String> cacheResults = jedis.mget(keys.toArray(cacheKeys));
List<TimeSeries> cachedTimeSeries = new ArrayList<TimeSeries>();
for(String cacheResult : cacheResults){
try {
retrieved = TimeSeriesPoints.parseFrom(cacheResult.getBytes());
TimeSeries timeSeries = new TimeSeries(retrieved.getName(), retrieved.getPointsList());
cachedTimeSeries.add(timeSeries);
}
catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
long pointsCount = 0;
for(TimeSeries timeSeries : cachedTimeSeries){
pointsCount += timeSeries.points.length;
}
System.out.println("retrieved: " + cachedTimeSeries.size());
System.out.println("points:" + pointsCount);
}
}
使用堆栈跟踪在 TimeSeriesPoints.parseFrom 处抛出异常,如下所示。不确定为什么。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.util.Arrays.copyOf(Unknown Source)
at java.util.ArrayList.ensureCapacity(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
at com.wimiro.caching.TimeSeriesProtos$TimeSeriesPoints.<init>(TimeSeriesProtos.java:115)
at com.wimiro.caching.TimeSeriesProtos$TimeSeriesPoints.<init>(TimeSeriesProtos.java:82)
at com.wimiro.caching.TimeSeriesProtos$TimeSeriesPoints$1.parsePartialFrom(TimeSeriesProtos.java:151)
at com.wimiro.caching.TimeSeriesProtos$TimeSeriesPoints$1.parsePartialFrom(TimeSeriesProtos.java:1)
at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:141)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:176)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:188)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:193)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:49)
at com.wimiro.caching.TimeSeriesProtos$TimeSeriesPoints.parseFrom(TimeSeriesProtos.java:958)
at program.main(program.java:77)
试图阅读800个时间序列(每个都有~4000个数据点)。由于我在这个例子中一次只处理50个时间序列,所以我不希望内存占用量大幅增长。
在.NET中,我没有遇到任何困难。是时候学习一些Java了。我需要阅读什么?
答案 0 :(得分:0)
您正在尝试从java String(UTF-16)获取字节数组,这些数组来自jedis(使用SafeEncoder将UTF-16转换为bytearray),该数组调用redis(C char 8位编码)。我认为这是你问题的根源,你的java字符串可能不正确,这会使protobuf失败。
您应该尝试使用jedis中的字节数组签名:
final List<byte[]> mget = jedis.mget(byteArray1, byteArray2, ...);
然后尝试在字节数组上使用protobuf。还要检查如何使用jedis在redis中插入数据,在所有情况下,建议将字节数组签名与二进制数据一起使用。
答案 1 :(得分:0)
不幸的是,Protobuf-Java对重复的基元类型使用了非常低效的编码 - 每个元素都是盒装的。例如。 repeated int32
表示为ArrayList<Int>
。从理论上讲,这可以在protobuf实现中进行优化,但最后我才知道这一点。我猜你的问题源于此。
如果您还没有,请尝试增加JVM的最大堆大小(例如,-Xmx2g
为2GB)。