我一直在实时流媒体项目中使用humble-video将flv转换为mp4。我已经意识到,当使用top命令查看时,java进程(运行简单视频代码)的内存使用量总是在增加。
之后,我更改了简陋视频的演示源代码,并将segmentFile function置于无限循环中,当使用top命令查看时,进程的内存使用率再次增加。它超过2.5GiB,已运行约30分钟。
我希望进程的内存消耗能够在40-50MB之间保持稳定,而不是始终保持增长。
你对此有什么想法吗?
答案 0 :(得分:0)
我已经解决了这个问题。
问题是垃圾收集器不清除WeakReferences,因此JNIMemoryManager不会删除本机对象。每次迭代后调用System.gc()都有帮助,但这不是确切的解决方案。
解决方案是在每次迭代结束时调用delete()。创建了一些在执行过程中可能没有预料到的对象,因此请查看使用JNIMemoryManager.getMgr().dumpMemoryLog();
创建的对象,并使用JNIMemoryManager.getMgr().getNumPinnedObjects();
查看有多少对象存在
segmentFile函数的最后一个状态如下所示,15min结束时内存消耗仍然保持在80 MiB左右。
private void segmentFile(String input, String output, int hls_start,
int hls_time, int hls_list_size, int hls_wrap, String hls_base_url,
String vFilter,
String aFilter) throws InterruptedException, IOException {
JNIMemoryManager.getMgr().setMemoryDebugging(true);
Demuxer demuxer = Demuxer.make();
demuxer.open(input, null, false, true, null, null);
// we're forcing this to be HTTP Live Streaming for this demo.
Muxer muxer = Muxer.make(output, null, "hls");
muxer.setProperty("start_number", hls_start);
muxer.setProperty("hls_time", hls_time);
muxer.setProperty("hls_list_size", hls_list_size);
muxer.setProperty("hls_wrap", hls_wrap);
if (hls_base_url != null && hls_base_url.length() > 0)
muxer.setProperty("hls_base_url", hls_base_url);
MuxerFormat format = MuxerFormat.guessFormat("mp4", null, null);
/**
* Create bit stream filters if we are asked to.
*/
BitStreamFilter vf = vFilter != null ? BitStreamFilter.make(vFilter) : null;
BitStreamFilter af = aFilter != null ? BitStreamFilter.make(aFilter) : null;
int n = demuxer.getNumStreams();
DemuxerStream[] demuxerStreams = new DemuxerStream[n];
Decoder[] decoders = new Decoder[n];
List<MuxerStream> muxerStreamList = new ArrayList();
for(int i = 0; i < n; i++) {
demuxerStreams[i] = demuxer.getStream(i);
decoders[i] = demuxerStreams[i].getDecoder();
Decoder d = decoders[i];
if (d != null) {
// neat; we can decode. Now let's see if this decoder can fit into the mp4 format.
if (!format.getSupportedCodecs().contains(d.getCodecID())) {
throw new RuntimeException("Input filename (" + input + ") contains at least one stream with a codec not supported in the output format: " + d.toString());
}
if (format.getFlag(MuxerFormat.Flag.GLOBAL_HEADER))
d.setFlag(Coder.Flag.FLAG_GLOBAL_HEADER, true);
d.open(null, null);
muxerStreamList.add(muxer.addNewStream(d));
}
}
muxer.open(null, null);
n = muxer.getNumStreams();
MuxerStream[] muxerStreams = new MuxerStream[n];
Coder[] coder = new Coder[n];
for (int i = 0; i < n; i++) {
muxerStreams[i] = muxer.getStream(i);
if (muxerStreams[i] != null) {
coder[i] = muxerStreams[i].getCoder();
}
}
MediaPacket packet = MediaPacket.make();
while(demuxer.read(packet) >= 0) {
/**
* Now we have a packet, but we can only write packets that had decoders we knew what to do with.
*/
final Decoder d = decoders[packet.getStreamIndex()];
if (packet.isComplete() && d != null) {
// check to see if we are using bit stream filters, and if so, filter the audio
// or video.
if (vf != null && d.getCodecType() == Type.MEDIA_VIDEO)
vf.filter(packet, null);
else if (af != null && d.getCodecType() == Type.MEDIA_AUDIO)
af.filter(packet, null);
muxer.write(packet, false);
}
}
// It is good practice to close demuxers when you're done to free
// up file handles. Humble will EVENTUALLY detect if nothing else
// references this demuxer and close it then, but get in the habit
// of cleaning up after yourself, and your future girlfriend/boyfriend
// will appreciate it.
muxer.close();
demuxer.close();
muxer.delete();
demuxer.delete();
packet.delete();
format.delete();
vf.delete();
muxer = null;
demuxer = null;
packet = null;
format = null;
vf = null;
for (int i=0; i < muxerStreams.length; i++) {
if (muxerStreams[i] != null) {
muxerStreams[i].delete();
muxerStreams[i] = null;
}
if (coder[i] != null) {
coder[i].delete();
coder[i] = null;
}
}
for (int i=0; i < demuxerStreams.length; i++) {
if (demuxerStreams[i] != null) {
demuxerStreams[i].delete();
demuxerStreams[i] = null;
}
if (decoders[i] != null) {
decoders[i].delete();
decoders[i] = null;
}
}
for (Iterator iterator = muxerStreamList.iterator(); iterator.hasNext();) {
MuxerStream muxerStream = (MuxerStream) iterator.next();
if (muxerStream != null) {
muxerStream.delete();
muxerStream = null;
}
}
muxerStreamList.clear();
muxerStreamList = null;
System.out.println("number of alive objects:" + JNIMemoryManager.getMgr().getNumPinnedObjects());
}