我正在申请一次播放30个视频。我使用Xuggler
解码视频文件和Swing
窗口进行显示。
但我遇到的问题如下:
如何调整垃圾收集器和其他性能参数,我应该注意什么?
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&amp;一般。我一次播放了所有30个视频。
更改位置(将IVideoPicture声明放在外面,只分配一次内存)可能有问题吗?每次在分配的内存上解码新的视频图像时,图像集的时间戳会被设置吗?
由于
答案 0 :(得分:3)
您当前的GC不适合您的任务。为了获得可预测的GC时序,您可以尝试使用G1垃圾收集器(我假设您使用的是Java 7u4或更高版本).G1计划作为并发标记扫描收集器(CMS)的长期替代品。将G1与CMS进行比较,存在差异,使G1成为更好的解决方案。 G1提供比CMS收集器更可预测的垃圾收集暂停,并允许用户指定所需的暂停目标。
使用以下选项来存档针对您的特定情况的最佳效果:
-XX:+ UseG1GC - 告诉JVM使用G1垃圾收集器。
-XX:MaxGCPauseMillis = 500 - 设置最大GC暂停时间的目标。这是一个软目标,JVM将尽最大努力实现它。因此,有时不会达到暂停时间目标。默认值为200毫秒。
-XX:InitiatingHeapOccupancyPercent = 80 - 启动并发GC循环的堆占用百分比。 G1使用它来根据整个堆的占用率触发并发GC循环,而不仅仅是其中一代。值0表示“执行恒定GC循环”。默认值为45%。
更多详细信息here
答案 1 :(得分:2)
一种方法是更改堆大小和不同代的大小。 GC Papre from Oracle解释了gc和调优的工作原理。
答案 2 :(得分:0)
我有这个建议:
当您需要非常精确的计时时,切勿使用Thread.sleep(long)
;使用Thread.sleep(0,long)
。这使用纳秒精度。
永远不要使用Thread.sleep
来精确重复任务。使用ScheduledExecutorService
并按照您需要的精确时间间隔安排任务。我亲眼目睹了这种方法比Windows上的睡眠方法更精确。
浏览你的代码,记下发生内存分配的每个地方,并思考+研究是否可以通过替换某些现有内存缓冲区的内容来替换分配。如果你取消分配,GC将很容易收集剩下的东西来收集。