一次内存泄露调试过程(1)


1.查看内存使用情况

cat /proc/meminfo
 其中SUnreclaim:695168 kB,随着测试时间加长SUnreclaim一直在增加,证明存在内存泄露可能.

2.查看slab分配信息 
cat /proc/slabinfo
其中skbuff_head_cache和kmalloc-1024分配的object数量达到8万个以上,而且还在不断增加,怀疑skb有内存泄露.
由于sysfs文件系统一次只能输出PAGE_SIZE大小的信息,导致 cat alloc_calls只能输出部分信息.而且也没有显示分配的调用堆栈

通过增加调试信息,过滤分配较少的slab输出,添加alloc stack信息.


跟踪到分配最频繁的调用栈为
cat /sys/kernel/slab/kmalloc-128/alloc_calls

 84050 __alloc_skb+0x68/0x1b4
[4]__alloc_skb+0x68/0x1b4
[5]tcp_send_ack+0x68/0x154
[6]__tcp_ack_snd_check+0x64/0x108
[7]tcp_rcv_established+0x364/0x740
[8]tcp_v4_do_rcv+0xa8/0x1b8
[9]tcp_v4_rcv+0x808/0xbd0
[10]ip_local_deliver_finish+0x1dc/0x370
[11]ip_local_deliver+0xe0/0x10c
[12]ip_rcv_finish+0x348/0x3e8


推测系统没有正确释放tcp ack包,而WIFI驱动支持DHDTCPACK_SUPPRESS功能。
直接看WIFI驱动hard_start_xmit函数对tcp ACK报文的处理逻辑
分析了dhd_tcpack_hold函数,当tcpack_info_tbl都被占用时,此时再来一个其他IP的tcp ack,
会hold,而又没有添加到tcpack_info_tbl ,从而导致tcp ack丢失。
bool
dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx)
{
   

    if (free_slot < TCPACK_INFO_MAXNUM) {
        /* No TCPACK packet with the same IP addr and TCP port is found
         * in tcp_ack_info_tbl. So add this packet to the table.
         */
        DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
            __FUNCTION__, __LINE__, pkt, new_ether_hdr,
            free_slot));

        tcpack_info_tbl[free_slot].pkt_in_q = pkt;
        tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr;
        tcpack_info_tbl[free_slot].ifidx = ifidx;
        tcpack_info_tbl[free_slot].supp_cnt = 1;
        mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer,
            jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay));
        tcpack_sup_mod->tcpack_info_cnt++;
    } else {
        DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
            __FUNCTION__, __LINE__)); //没有可使用的ack info tbl时,需要把hold设置成 false ,直接发送tcp ack
    }
    dhd_os_tcpackunlock(dhdp, flags);

exit:
    return hold;
}

如果发现是kmalloc-128 分配的object个数大,需要减少kmalloc的粒度再测试
#define ARCH_KMALLOC_MINALIGN 8 //最小分配为8 Byte
#define KMALLOC_MIN_SIZE 8
#define KMALLOC_SHIFT_LOW 3

解决内存泄露的问题,也可以用KMEMLEAK 排查。配置 CONFIG_DEBUG_KMEMLEAK,并在 cmdline 中加入 kmemleak=on

猜你喜欢

转载自blog.csdn.net/bin_linux96/article/details/79496803