3

一度に 30 本の動画を再生するアプリケーションを使用しています。ビデオファイルとウィンドウXugglerをデコードして表示するために使用しています。Swing

しかし、私は次のような問題に直面しています:

  1. 動画がスムーズに表示されない
  2. 私が見つけたプロファイラーでは、約 25% の時間がガベージ コレクションに費やされていました。

ガベージ コレクターを調整するにはどうすればよいですか? また、その他のパフォーマンス パラメータにはどのような注意が必要ですか?

Xuggler と Java の組み合わせは良くないですか?

編集

私のビデオデコードループは次のとおりです。

private boolean decodeStreams() throws Exception {
    IPacket packet = IPacket.make();

    long firstTimestampInStream = Global.NO_PTS;
    long systemClockStartTime = 0;

    viewer.urlStatusUpdate(index, Globals.STATUS_PLAYING);

    while (container.readNextPacket(packet) >= 0) {
        if (stopPlaying) {
            if (isStopPlaying(2)) {
                return false;
            }
        }

        if (packet.getStreamIndex() == videoStreamID) {
            IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight());
            int offset = 0;
            while (offset < packet.getSize()) {
                int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset);
                if (bytesDecoded < 0) {
                    throw new Exception("Got error on decoding video");
                }
                offset += bytesDecoded;
                if (picture.isComplete()) {
                    if (firstTimestampInStream == Global.NO_PTS) {
                        firstTimestampInStream = picture.getTimeStamp();
                        systemClockStartTime = System.currentTimeMillis();
                    } else {
                        long millisecondsToSleep = (
                                ((picture.getTimeStamp() - firstTimestampInStream) / 1000)
                                - (System.currentTimeMillis() - systemClockStartTime)
                                );
                        if (millisecondsToSleep > 50) {
                            try {
                                Thread.sleep(millisecondsToSleep - 50);
                            } catch (Exception e) {
                            }
                        }
                    }
                    viewer.videoImageUpdate(index, converter.toImage(picture));
                }
            }
        }
    }

    return true;
}

そして、IVideoPicture 宣言の場所を変更しました。

private boolean decodeStreams() throws Exception {
    IPacket packet = IPacket.make();

    long firstTimestampInStream = Global.NO_PTS;
    long systemClockStartTime = 0;

    viewer.urlStatusUpdate(index, Globals.STATUS_PLAYING);
    IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight());

    while (container.readNextPacket(packet) >= 0) {
        if (stopPlaying) {
            if (isStopPlaying(2)) {
                return false;
            }
        }

        if (packet.getStreamIndex() == videoStreamID) {
            int offset = 0;
            while (offset < packet.getSize()) {
                int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset);
                if (bytesDecoded < 0) {
                    throw new Exception("Got error on decoding video");
                }
                offset += bytesDecoded;
                if (picture.isComplete()) {
                    if (firstTimestampInStream == Global.NO_PTS) {
                        firstTimestampInStream = picture.getTimeStamp();
                        systemClockStartTime = System.currentTimeMillis();
                    } else {
                        long millisecondsToSleep = (
                                ((picture.getTimeStamp() - firstTimestampInStream) / 1000)
                                - (System.currentTimeMillis() - systemClockStartTime)
                                );
                        if (millisecondsToSleep > 50) {
                            try {
                                Thread.sleep(millisecondsToSleep - 50);
                            } catch (Exception e) {
                            }
                        }
                    }
                    viewer.videoImageUpdate(index, converter.toImage(picture));
                }
            }
        }
    }

    return true;
}

現在、GC は 10% 未満の時間を費やしており、通常は約 5% から 8% です。そして、一度に 30 本すべてのビデオをスムーズに再生できました。

場所の変更 (IVideoPicture 宣言を外部に配置し、メモリを 1 回だけ割り当てる) は問題になる可能性がありますか? 新しいビデオ画像が割り当てられたメモリでデコードされるたびに、画像のタイムスタンプが設定されますか?

ありがとう

4

3 に答える 3

3

現在の GC があなたのタスクに合わない可能性があります。予測可能な GC タイミングを取得するには、G1 ガベージ コレクターを使用してみてください (Java 7u4 以降を使用していると想定しています)。G1 は、Concurrent Mark-Sweep Collector (CMS) の長期的な代替品として計画されています。G1 と CMS を比較すると、G1 をより優れたソリューションにする違いがあります。G1 は、CMS コレクターよりも予測可能なガベージ コレクションの一時停止を提供し、ユーザーが目的の一時停止ターゲットを指定できるようにします。

次のオプションを試して、特定のケースで最高のパフォーマンスをアーカイブしてください。

-XX:+UseG1GC - JVM に G1 ガベージ コレクタを使用するように指示します。

-XX:MaxGCPauseMillis=500 - 最大 GC 一時停止時間の目標を設定します。これはソフトな目標であり、JVM はそれを達成するために最善を尽くします。したがって、一時停止時間の目標が達成されない場合があります。デフォルト値は 200 ミリ秒です。

-XX:InitiatingHeapOccupancyPercent=80 - 同時 GC サイクルを開始するためのヒープ占有率。ジェネレーションの 1 つだけでなく、ヒープ全体の占有率に基づいて同時 GC サイクルをトリガーするために、G1 によって使用されます。値 0 は、「一定の GC サイクルを実行する」ことを示します。デフォルト値は 45% です。

詳細はこちら

于 2013-07-28T09:49:00.913 に答える
2

1 つの方法は、異なる世代のヒープ サイズとサイズを変更することです。OracleのGC Papre は、GCとチューニングがどのように機能するかを説明しています。

于 2013-07-28T09:42:22.247 に答える
0

私はこのアドバイスを持っています:

  1. Thread.sleep(long)非常に正確なタイミングが必要な場合は使用しないでください。使用してThread.sleep(0,long)ください。これはナノ秒の精度を使用します。

  2. 正確に繰り返すタスクには絶対に使用Thread.sleep しないでください。を使用してScheduledExecutorService、必要な正確な間隔でタスクをスケジュールします。私は個人的に、この方法が Windows のスリープ方法よりもはるかに正確であることを目の当たりにしました。

  3. コードを調べて、メモリ割り当てが発生する各場所に注意し、既存のメモリ バッファーの内容を置き換えるだけで割り当てを置き換えることができるかどうかをよく考えて調査してください。割り当てを下げると、GC は収集するために残っているわずかなものを簡単に収集できます。

于 2013-07-28T11:45:11.767 に答える