Frage

I am having application to play 30 videos at a time. I am using Xuggler to decode video files and Swing windows for display.

But I am facing problems like:

  1. Videos not displaying smooth
  2. With profiler I found, around 25% time was spending for garbage collection.

How can I tune garbage collector and what other performance parameters, I should take care?

Is Xuggler-Java combination not good?

EDIT

My video decoding loop was:

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;
}

And I changed place of IVideoPicture declaration:

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;
}

Now GC is spending less than 10% time, around 5% to 8& normally. And I got all 30 videos playing smoothly at a time.

Is changing place (Putting IVideoPicture declaration outside, and allocating memory only once) can be problem? Will timestamps of picture set everytime new video picture is decoded on allocated memory?

Thanks

War es hilfreich?

Lösung

Chances are that your current GC ill suits your task. To get a predictable GC timings you may try to use G1 garbage collector (I'm assuming you're on Java 7u4 or later).G1 is planned as the long term replacement for the Concurrent Mark-Sweep Collector (CMS). Comparing G1 with CMS, there are differences that make G1 a better solution. G1 offers more predictable garbage collection pauses than the CMS collector, and allows users to specify desired pause targets.

Play with the following options to archive the best performance for your particular case:

-XX:+UseG1GC - Tells the JVM to use the G1 Garbage collector.

-XX:MaxGCPauseMillis=500 - Sets a target for the maximum GC pause time. This is a soft goal, and the JVM will make its best effort to achieve it. Therefore, the pause time goal will sometimes not be met. The default value is 200 milliseconds.

-XX:InitiatingHeapOccupancyPercent=80 - Percentage of the heap occupancy to start a concurrent GC cycle. It is used by G1 to trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations. A value of 0 denotes 'do constant GC cycles'. The default value is 45%.

More details available here

Andere Tipps

One way would be to change the heap size and the size off the diffrent generations. The GC Papre from Oracle explains how the gc and the tuning works.

I've got this advice:

  1. Never use Thread.sleep(long) when you need very precise timing; use Thread.sleep(0,long). This uses nanosecond precision.

  2. Never use Thread.sleep at all for precisely repeating tasks. Use a ScheduledExecutorService and schedule the task at the precise interval you need. I have personally witnessed this method being way more precise than the sleep method on Windows.

  3. Go through your code, note each place where memory allocation happens, and think+research hard whether the allocation can be replaced by just replacing the contents of some existing memory buffer. If you bring down the allocation, the GC will have an easy time collecting what little there is left to collect.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top