1

以下のコードを実行すると、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 を学ぶ時間です。何を読む必要がありますか?

4

2 に答える 2

1

残念なことに、Protobuf-Java は、繰り返されるプリミティブ型に対して非常に非効率的なエンコーディングを使用します。各要素はボックス化されています。たとえば、 arepeated int32は として表されArrayList<Int>ます。理論的には、これは protobuf の実装で最適化できますが、これは私が最後に知っていたものではありませんでした。あなたの問題はこれから生じると思います。

まだ行っていない場合は、JVM の最大ヒープ サイズを増やしてみてください (例: -Xmx2g2GB)。

于 2014-03-12T10:04:48.303 に答える