在接到这个任务的时候,对FreeSwitch处于一问三不知的情况,不了解FreeSwitch的业务,不了解流程,更要不要说代码了。但是还是硬着头皮上了,原本以为是个短期接触战,没想到被自己搞成了持久战。回过来头看,一开始对任务的难度还是低估了,没有做好持久战的准备。
在接到任务后,在没有先去了解业务的情况下,就开始了各种尝试。
工具1:valgrind,跑了一段时间后,除了输出一堆无用的垃圾外,没什么用
工具2:fmpool,开源的工具,使用该工具后,性能下降明显,需要跑较长时间,才能输出一些有用的信息
工具3:gperftool,google开源的工具,使用该工具,同样性能也下降了,也需要跑较长时间,但是输出的信息很有用。可以明显的看到泄漏路径。
但是拿到这个内存泄漏图后,不了解底层代码的情况,根本看不懂。更不要说如何修改了。
在选择内存泄漏排查工具的过程中,还是走了一些弯路。一度怀疑是内存空洞造成的内存泄漏。然后看明面上的freeswitch日志,以为是视频通话场景下,分配了大量的jitter_buffer造成的内存空洞,然后导致了泄漏。在这个方向上,浪费了很多时间。
唯一的收获是了解了apr库内存池的使用,以及排除了session和channel层内存泄漏的可能性。
后面XX告诉我84环境freeswitch有内存泄漏的情况,用上了gperftool后,输出的内存泄漏路径都在sofia-sip库。但是底层代码没人熟悉,只能沉下来心来,去啃这块硬骨头了。
在梳理内存泄漏路径的过程中,发现sofia-sip库的内存分配是基于Home-base的内存分配机制。什么意思?就是sofia-sip库的内存分配,会先分配一个home的内存,然后需要再次分配内存的时候,通过这个home来分配,释放的时候也有home来释放。所以只要抓注su_home_new和su_home_deinit,就抓注了内向泄漏的重点了。
原来的日志比较简单,后面打开了很多调试级别的日志,以及在su_alloc.c加上日志调试,就能清晰的看到一个的流程所有日志。通过大量的阅读日志和代码,终于定位到是两个场景触发的内存泄漏。
一个是无效注册请求包。无效注册请求就是在userinfo表没有记录的用户的请求,原来的流程是没有做这个判断,然后会回复401。后面是改成了,不回复401就完事了。这样导致了分配的handle,soa_session,message的内存都没有被释放。
一个是无效INVITE包。无效INVITE包也是在userinfo表没有记录的用户请求。原来的流程是没有做这个判断,然后会回复407。后面是改成了,将IP加入黑名单,后面就不会收到这个IP的包。但是在测试环境中并没有加入黑名单的动作,所以出现了大量的内存泄漏。
原代码:判断用户非法后没有给响应,导致申请的nua_handle,message,soa_session的Home内存没有被释放
if (regtype == REG_REGISTER) {
if(switch_akcs_check_valid_user(de->sip->sip_to->a_url->url_user) > 0)
{
nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
}
} else if (regtype == REG_INVITE) {
if(switch_akcs_check_valid_user(de->sip->sip_from->a_url->url_user) > 0)
{
nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,
TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)),
SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
}
else if(switch_akcs_check_valid_user(de->sip->sip_to->a_url->url_user) <= 0)
{
//拉入黑名单
char network_ip[80] = {0};
//int network_port = 0;
//sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
//added by chenyc, 2019-12-06 加入业务限制记录中
//AddBussiness(network_ip);
if(de->sip->sip_via)
{
sip_via_t *via = NULL;
for (via = de->sip->sip_via; via->v_next; via = via->v_next)
{
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "via ip:%s port:%s\n",via->v_host, via->v_port);
}
switch_copy_string(network_ip, via->v_host, sizeof(network_ip));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid user:%s,from ip:%s\n",de->sip->sip_to->a_url->url_user,network_ip);
switch_akcs_add_bussiness(network_ip);
}
}
}
修复方法:
if (regtype == REG_REGISTER) {
if (switch_akcs_check_valid_user(de->sip->sip_to->a_url->url_user) > 0) {
nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
} else {
nua_respond(nh, SIP_403_FORBIDDEN, TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)), TAG_END());
}
} else if (regtype == REG_INVITE) {
if (switch_akcs_check_valid_user(de->sip->sip_from->a_url->url_user) > 0) {
nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,
TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)),
SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
} else if (switch_akcs_check_valid_user(de->sip->sip_to->a_url->url_user) <= 0) {
//拉入黑名单
char network_ip[80] = {0};
//int network_port = 0;
//sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
//added by chenyc, 2019-12-06 加入业务限制记录中
//AddBussiness(network_ip);
if (de->sip->sip_via) {
sip_via_t *via = NULL;
for (via = de->sip->sip_via; via->v_next; via = via->v_next) {
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "via ip:%s port:%s\n",via->v_host, via->v_port);
}
switch_copy_string(network_ip, via->v_host, sizeof(network_ip));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid user:%s,from ip:%s\n", de->sip->sip_to->a_url->url_user, network_ip);
switch_akcs_add_bussiness(network_ip);
}
nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,
TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)),
SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
}
}
从不知所措到最终攻克这个难题,坚持很重要。每个人都会有畏难的心态,但是要学会去克服,释放自己的压力。怎么克服呢?
1、把困难当作历练提升的契机。像这次内存泄漏定位,就是很好的了解freeswitch的机会,借着这次机会,提升了对sofia-sip的底层的理解。
2、把自己的压力讲出来。
3、关注过程更甚于关注结果。如果目标比较远,需要时间累积。一直望著遥远的目标没有帮助,只是增加现在不想开始的藉口。改为关注自己每一次迈进的步伐,只要方向正确,比什么都没有开始好。