您的位置:首页 > 其它

live555学习笔记16-几个重要对象的生命期

2011-12-19 09:13 489 查看
十六 几个重要对象的生命期

live555中很多类,类与类之间的关系复杂,从属关系不明显,层次上看起来也有些乱.所以源代码读起来比较困难,对于一些对象生命的来龙去脉也很难厘清.

但这并不能说明live555的架构不好,最适合的才是最好的,对于流媒体的处理来说,live555架构已是相当精巧,当然,这是在你深入了解它的基础上才会有的体会.

live555作为服务器,大家都很关心对内存的利用效率,是否过多的吃内存?是否造成太多的内存碎片?

我个人认为不必太担心这方面的事,live555对于内存的使用效率还是比较高的,当然要求太高的可能要自己实现内存池之类的东西.

然而,我在使用它的过程中,还是发现了一点小小的问题,这个问题只在某些情况下起作用.

在此不对内存管理做全面的阐述,只是探讨一下live555中一些重要类的对象实体是怎样被销毁的,同时说明那点小问题.

首先说创世者:是RTSPServer:它需永存,其余对象都是由它创建或由它引起了它们的创建.

RTSPServer直接掌管的是ServerMediaSession和RTSPClientSession(只主其生,不掌其死).

ServerMediaSession对应一个媒体文件,而RTSPClientSession对应一个RTSP客户连接.RTSPClientSession在客户发出RTSP的TCP连接时建立,而ServerMediaSession在客户发出对一个新文件的DESCRIBE时建立.建立ServerMediaSession的同时也建立了ServerMediaSubsession们,被ServerMediaSession所管理,代表一个文件中的track们.

ServerMediaSession的建立规则值得一说:RTSPClientSession在收到客户的DESCRIBE请求时,跟据地址中的媒体名字,去查找ServerMediaSession的列表,如果已有对应此媒体名字的ServerMediaSession,则利用它获取SDP信息.如果没找到,则跟据媒体名字中的扩展名部分,建立对应此类媒体的新ServerMediaSession对象.所以可以明确一点:一个ServerMediaSubsession对应一个文件!

但是,如果测试,你会发现当一个文件播放完毕之后,并没有删除对应的ServerMediaSession.同时,与ServerMediaSubsession相关的那一坨东西(Demux和ServerMediaSubsession)也没有被销毁.但是它们终究还是要面临死亡的.什么时候死呢?RTSPServer销毁的什候(或对应的文件不存在了时)!哦,看到问题了吧?如果你做点播服务器,每打开一个文件就会创建一个ServerMediaSession以及相关的一坨东西们,如果文件太多,内存终究有用完的时候.

再说一下RTSPClientSession,RTSPClientSession有两种结束生命的方式,一是在对应流(StreamState)接收不到RTCP数据了,还记得前面讲过RTCPInstance的setSpecificRRHandler()吗?RTSPClientSession就是通过它来监视客户端的心跳的.二种方式是收到客户端的TEARDOWN请求时自杀.RTSPClientSession自杀的同时会把流对象StreamState以及流上的Source和sink全干掉.

所以说,除了RTSPClientSession那一坨之外,其余的对象还是可以在适当的时候销毁的.基本上是代表静态数据的对象不销毁,而代表动态数据的对象销毁.

如果你做的是实时流媒体,那么这正是所需要的.而做点播服务呢?总不能文件关了,代表文件的对象还在内存中吧?

那我们如何去改呢?

其实很简单,我们只要在没有任何对ServerMediaSession的引用时把它删除不就行了.而且ServerMediaSession中已经实现了引用计数,见如下三个函数:

unsigned referenceCount() const
{
return fReferenceCount;
}
void incrementReferenceCount()
{
++fReferenceCount;
}
void decrementReferenceCount()
{
if (fReferenceCount > 0)
--fReferenceCount;
}


现在的问题是何时减少这个引用计数.可以想象,基本情况是在建立一个新的StreamState时或建立RTSPClientSession时,ServerMediaSession的引用就会增加1.那么理应在RTSPClientSession关闭时减去1.我们看看源码,是否是这样做了?

经查找,是在建立新的StreamState时.在函数void RTSPServer::RTSPClientSession::handleCmd_SETUP(char const* cseq,char const* urlPreSuffix, char const* urlSuffix,char const* fullRequestStr)中可以看到.再找一下减少引用的代码:

RTSPServer::RTSPClientSession::~RTSPClientSession()
{
closeSockets();

if (fSessionCookie != NULL)
{
// We were being used for RTSP-over-HTTP tunneling.  Remove ourselves from the 'session cookie' hash table before we go:
fOurServer.fClientSessionsForHTTPTunneling->Remove(fSessionCookie);
delete[] fSessionCookie;
}

reclaimStreamStates();

if (fOurServerMediaSession != NULL)
{
fOurServerMediaSession->decrementReferenceCount();
if (fOurServerMediaSession->referenceCount() == 0
&& fOurServerMediaSession->deleteWhenUnreferenced())
{
fOurServer.removeServerMediaSession(fOurServerMediaSession);
fOurServerMediaSession = NULL;
}
}
}
是在RTSPClientSession销毁时减少引用.同时我们还看到

if (fOurServerMediaSession->referenceCount() == 0
&& fOurServerMediaSession->deleteWhenUnreferenced())
{
fOurServer.removeServerMediaSession(fOurServerMediaSession);
fOurServerMediaSession = NULL;
}
这样的语句,翻译过来就是:当引用为0并且可以在引用为0时删除,那么就删除它!原来在这里!我们只要让他deleteWhenUnreferenced()能返回True就解决上面所说的那个小问题了.

等等,似乎还有问题,ServerMediaSession是RTSPClientSession在建立StreamState时增加引用,而在RTSPClientSession销毁时减少引用,如果有多个Track,StreamState是要被创建多次的?好像引用增加与减少对不起来啊!真的是这样吗?我没测试我不敢说,嘿嘿,那就先留个悬念吧.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: