深入理解内存泄漏检查kmemleak

原创 Linux阅码场 2022-02-25 08:00

作者简介

bang,linux内核爱好者,目前就职于杭州某安防公司,主要从事于SOC的bring up及驱动开发,喜欢分析linux内核内存管理和调度子系统。



1.概述


内存泄漏是我们工作中经常遇到的问题,比如随着业务的持续运行,系统中可用内存在快速减少,导致某个重要的业务进程被OOM kill掉了。内存泄漏往往都是很严重的问题,尤其是内核态的内存泄漏,危害更大。每次泄漏一块内存,该块内存就成为一个黑洞,如果是严重的内核态内存泄漏,系统将很快变的无法正常使用,通常需要重启设备或者服务器才能解决问题。我们肯定不希望这种事情发生,那就需要想办法把内存泄漏提前暴露在测试环境中。要解决内存泄漏问题,首先需要了解内存泄漏的特点。内存泄漏分为用户态的内存泄漏和内核态的内存泄漏,我们本文主要关注的是内核态的内存泄漏。工作中比较常见的内存泄漏按照发生泄漏的频率可以划分以下几种类型:


  • 1、一次性内存泄漏,只在初始化过程中或某一次条件触发产生的内存泄漏。

  • 2、偶发性内存泄漏,在某种条件下偶尔触发产生的内存泄漏。

  • 3、频发性内存泄漏,内存泄漏点被频繁的触发。


对于频发性内存泄漏我们有比较多的调试手段去定位,比如我们可以先通过/proc/meminfo信息大致确定下内存泄漏发生在哪个模块中,再通过其他手段进一步定位。如果观察到vmalloc异常,可以通过/proc/vmallocinfo信息分析定位。如果观察到slab内存异常,可以通过slabinfo/sys/kernel/slab/*/alloc_callsfree_calls去辅助定位问题。而对于一次性的或者偶发性的内存泄漏确很难去通过/proc/meminfo信息快速分析定位,且大量的一次性或偶发性内存泄漏,同样给系统造成额外的内存压力。而本文介绍的kmemleak工具为各种类型的内存泄漏提供了一种检测方法。


2.原理


kmemleak(kernel memory leak detector)是检测内核空间的内存泄漏的调试工具。检测对象是memblock_allockmallocvmallockmem_cache_alloc等函数分配的内存块,该内存块由struct kmemleak_object来描述(简称为object)kmemleak的实现原理非常简单,通过暴力扫描内存(假定内存中存放的都是指针,以ARM64为例,每次扫描8个字节),如果找不到指向起始地址或者内存块任何位置的指针,则分配的内存块被认为是孤立的。这意味着内核可能无法将分配内存块的地址传递给释放函数,因此该内存块被视为内存泄漏。内存块(object)有3种颜色,分别为黑色、白色、灰色, 通过count和min_count区分不同颜色的object。


黑色: min_count = -1,表示被忽略的object,此object不包含对别人的引用,也不会存在内存泄漏,比如代码段会标记为黑色。


白色: count < min_count,孤立的object,没有足够的引用指向这个object,一轮扫描结束后被认为泄漏的内存块。


灰色: min_count = 0,表示不是孤立的object,即不存在内存泄漏的object,如代码中主动标记object为灰色,防止误报(如data、bss、ro_after_init)。或者count >= min_count,对该object有足够的指针引用,认为不存在内存泄漏的内存块。


具体检测步骤如下:


  • 1、通过struct kmemleak_object(简称为object)描述kmallocvmallockmem_cache_alloc等函数申请的内存块,记录申请内存的起始地址,大小、call trace等信息。同时把object加入到红黑树object_tree_root和双向链表object_list中,红黑树中的key值为内存块的起始地址。


  • 2、遍历双向链表object_list,把所有的objectcount计数清0,即在新的一轮扫描前,尽可能的把能复位成白色的object标记为白色。然后判断object是否是灰色(默认databssro_after_init段会被标记为灰色),如果是灰色的object则把object加入到灰色链表gray_list中。


  • 3、扫描内存中可能存放指针的内存区域(per-cpu段、struct page的内容、内核栈、灰色链表),根据挂在红黑树中所有的object的地址范围进行对比。如果有指针指向某一个object(指向该object的起始地址或者指向object地址范围内),会把object对应的count字段增加1,如果object变成灰色,则会把object加入到灰色链表中。


  • 4、扫描object_list中的白色对象的object,判断object所描述的地址范围的内容的crc值是否发生变化,如果发生变化,则同样把object加入到灰色链表gray_list中。说明通过间接的方式访问了object描述的地址范围,不是内存泄漏,减少误报。


  • 5、重新扫描灰色链表,因为步骤4中,可能有些白色的object加入到了灰色链表中,需要重新扫描。


  • 6、经过上述一系列的扫描,剩余白色的object就是可疑的内存泄漏点。 

3.数据结构


3.1、kmemleak_object


struct kmemleak_object描述一段通过memblock_allockmallocvmallockmem_cache_alloc等函数分配的内存块。此内存块会加入到红黑树object_tree_root和双向链表object_list中。


struct kmemleak_object {    raw_spinlock_t lock;    unsigned int flags;         struct list_head object_list;    struct list_head gray_list;    struct rb_node rb_node;         atomic_t use_count;    unsigned long pointer;    size_t size;    unsigned long excess_ref;    int min_count;    int count;    u32 checksum;    struct hlist_head area_list;    unsigned long trace[MAX_TRACE];    unsigned int trace_len;    unsigned long jiffies;      /* creation timestamp */    pid_t pid;          /* pid of the current task */    char comm[TASK_COMM_LEN];   /* executable name */};



lockspinlock锁用于保护当前的object对象。


flagsobject的状态标志位。有以下状态标志位:


  • OBJECT_ALLOCATED:表示已经分配的内存块的状态标志。在创建object的时候,会置上此标记,在释放object的时候,清除此标记。


  • OBJECT_REPORTED:表示经过一轮内存扫描之后,把有内存泄漏风险object的flags置上OBJECT_REPORTED,然后用户可以通过cat /sys/kernel/debug/kmemleak获取有内存泄漏风险的object。


  • OBJECT_NO_SCAN:表示不去扫描此内存块。kmemleak为了减少误报和漏报,通过封装好的接口设置内存块是否需要扫描,如果不需要扫描则flags置上OBJECT_NO_SCAN标志。


  • OBJECT_FULL_SCAN:表示当内存不足分配scan_area失败的时候,把当前的object标记为OBJECT_FULL_SCAN,表示此objcet全部扫描,不再是局部扫描


object_list:通过该字段把objec添加到object_list链表中。


gray_list:通过该字段把object添加到gray_list链表中。


rb_node:通过该字段把object添加到object_tree_root的红黑树中。


use_count:object使用计数。通过get_object增加计数,put_object减少计数,当use_count = 0时释放该object。


pointer:object的起始地址。


size:object的大小。


excess_ref:具体见kmemleak_vmalloc函数实现。


min_count:指向内存块的最少指针个数。如果小于该值,说明有内存泄漏的嫌疑。


count:扫描到的指向内存块的指针总数,和min_count配合使用。


checksum:内存块的CRC校验和。


area_list:如果area_list链表为NULL,则以object的pointer为起始地址和size为大小的地址范围扫描。如果不为NULL,以area_list链表中的kmemleak_scan_area节点的start和size为地址范围扫描。一个object描述的内存块可能被分割为多个kmemleak_scan_area区域,所有的kmemleak_scan_area通过node节点添加到area_list为头的链表中。


trace:保存创建object的stack trace的地址。


trace_len:表示stack trace的实际深度,最大深度为MAX_TRACE(16)。


jiffies:创建object时的jiffies。


pid:表示创建objcet的pid号。


comm:创建object的进程名。


3.2、kmemleak_scan_area


struct kmemleak_scan_area内存块的扫描区域描述符。为了降低误报,限制所属的object描述的内存块的扫描范围,对object描述的地址范围划分为不同的kmemleak_scan_area区域进行扫描。


/* scanning area inside a memory block */struct kmemleak_scan_area {                                                                                                                                                    struct hlist_node node;    unsigned long start;    size_t size;};


3.3、全局变量


object_list:新创建的object会挂入到全局的objcet_list链表中。


gray_list:如果object不存在内存泄漏的风险,会把object加入到gray_list链表中,表示不存在内存泄漏风险的object。


object_tree_root:为了加快查询速度,新创建的object,不仅会加入到object_list全局链表中,同时会加入到object_tree_root为根的红黑树,红黑树的key值为object的起始地址。


min_addr:所有object中最小的起始地址。有可能最小起始地址的object已经不在object链表中或者红黑树中。目的是为了对检测的地址进行简单的过滤。


max_addr:所有object中最大的结束地址。有可能最大结束地址的object已经不在object链表中或者红黑树中。目的是为了对检测的地址进行简单的过滤。


jiffies_last_scan:开始扫描时候的jiffies。


jiffies_min_age:为了减少误报,避免报告最近分配的object。因为最近分配的object的指针有可能临时存放在cpu的寄存器中。默认值为MSECS_MIN_AGE(5s)。通过unreferenced_object函数可以看出上报有内存泄漏风险的object,需要在此扫描周期开始的T0之前创建object。而T0之后到扫描结束之间创建的object,要在下一个周期进行扫描检测。



static bool unreferenced_object(struct kmemleak_object *object){    return (color_white(object) && object->flags & OBJECT_ALLOCATED) &&        time_before_eq(object->jiffies + jiffies_min_age,                                                                                                                              jiffies_last_scan);}

jiffies_scan_wait:两次扫描的时间间隔SECS_SCAN_WAIT默认为60s。


4.kmemleak代码实现


4.1、kmemleak_init


void __init kmemleak_init(void){#ifdef CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF    if (!kmemleak_skip_disable) { /* 1 */        kmemleak_disable();        return;    }#endif    /* register the data/bss sections */ /* 2 */    create_object((unsigned long)_sdata, _edata - _sdata,              KMEMLEAK_GREY, GFP_ATOMIC);    create_object((unsigned long)__bss_start, __bss_stop - __bss_start,              KMEMLEAK_GREY, GFP_ATOMIC);    /* only register .data..ro_after_init if not within .data */    if (&__start_ro_after_init < &_sdata || &__end_ro_after_init > &_edata)        create_object((unsigned long)__start_ro_after_init,                  __end_ro_after_init - __start_ro_after_init,                  KMEMLEAK_GREY, GFP_ATOMIC);}


  • 1、如果定义了CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏或者通过cmdline设置为kmemleak=off则默认关闭kmemleak。如果cmdline中设置kmemleak=on则表示默认开启kmemleak功能。如果没有定义CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏,则默认是开启kmemleak功能。


  • 2、创建data段、bss段、.data..ro_after_init段对应的object


思考


问题一为什么不直接静态扫描这些段的内容,而是需要通过object的方式进行管理?


:因为这些section的某些区域可能被动态的释放(如bss段),如果静态扫描可能产生page fault,进一步产生kenrel panic。所以这里采用创建object的方式去扫描bss段,同时把此object标记为灰色,因为这个object描述的内存块不存在内存泄漏。当需要释放bss段的某些区域的时候通过调用kmemleak_free_part函数动态的把bss段进行分割成不同的新的object。(扣除释放的区域)


问题二:为什么需要判断.data..ro_after_init段的范围?


:.data..ro_after_init段表示在内核初始化过程中这个段是可读写的,在初始化完成之后把该段修改为只读。不同的架构的.data..ro_after_init段位于不同的区域,有的直接属于data段,有些会归到rodata段中。如果在data段里,则无需再创建object,如果不在data段内,则需要创建对应的object。


4.2、create_object

 



创建一个object对象,并object的成员进行初始化,同时把object加入到红黑树和双向链表中。假设新创建的object起始地址为10,如下图所示:

 


4.3、delete_object_full/delete_object_part


 

delete_object_full删除整个object,把object从红黑树中和双向链表中删除,同时释放object对应的内存。


 

delete_object_part切割object对象,把完整的object进行切割,有4种情况:


  • 1、左边删除,只留右边的区域,以右边区域为内存块,创建一个新的object

  • 2、右边删除,只留左边的区域,以左边区域为内存块,创建一个新的object

  • 3、刚好完全删除整个object描述的区域,等价于delete_object_full

  • 4、删除中间区域,留两边区域,创建两个新的object

 


put_object递减object的引用计数,如果引用计数为0,则把object进行释放。


4.4、创建object的api接口分析


api接口函数

分析

kmemleak_alloc

kmemleak_alloc直接调用create_object函数,ptr、size、min_count由使用者指,如kmalloc、slab/slub/slob函数。min_count为1,表示至少有一处指针指向申请的内存块。

kmemleak_alloc_percpu

kmemleak_alloc_percpu函数需要对每个cpu都调用一次create_object函数,其中min_count为0,表示percpu区域的内存不存在内存泄漏,即默认为灰色object。

kmemleak_vmalloc

kmemleak_vmalloc函数首先调用create_object创建一个新的object,但min_count为2,即表示最少有两处指针指向内存块才能说明vmalloc申请的内存块没有产生泄漏。同时把area->addr设置到object->excess_ref字段中。

kmemleak_alloc_phys

kmemleak_alloc_phys函数的起始地址为物理地址,主要用于memblock机制中memblock_alloc申请的内存块。且min_count为0,表示memblock_alloc申请的内存块默认为灰色object,不存在内存泄漏,只对内存块内容扫描。


思考:


1、kmemleak_vmalloc中为什么min_count等于2?

 


从图中我们可以看出,struct vm_struct中的addr字段指向vmalloc申请的内存块,strct vmap_area中的va_start字段也指向了vmalloc申请的内存块。同时我们可以知道vmalloc的返回值肯定也保存在某个变量中。理论上至少有3处指针指向了vmalloc的内存块的起始地址,为什么min_count为2?因为strct vmap_area中va_start字段在alloc_vmap_area函数中通过kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask)函数给过滤掉了,所以min_count为2。


2、kmemleak_vmalloc中为什么要把area->addr设置到vm_struct内存块对应的object的excess_ref字段中?


答:考虑这样一种场景,vmalloc申请的内存块的起始地址,并没有被直接引用,而是通过一个全局指针struct vm_struct *tmp 间接引用。我们可以得到如下信息:


1、tmp可以通过vm_struct间接的访问vmalloc的区域。

2、vm_struct的指针同时也被保存在vmap_area中。

通过上面信息我们可以知道扫描全局指针tmp的时候会把vm_struct内存块对应的object加入到灰色链表中。扫描vmap_area的时候遍历到vm_struct指针的时候,发现指针对应的object已经加入到灰色链表中,不做处理,然后在扫描vm_struct所在内存块对应的object的灰色链表的时候,扫描到addr字段的时候,把addr对应的vmalloc区域的object的count++。此时count 1) < min_count2)会报内存泄漏。其实不是内存泄漏,因为我们可以通过tmp指针间接的找到vmalloc的addr。所以如果我们发现vm_struct对应的object已经变为灰色了,我们需要确定下vm_struct中addr字段是否在红黑树中能找到对应的object?如果能找到,则把addr对应的object的count++。因此对于vmalloc申请的区域,我还需要检查对vm_struct引用次数。如果大于等于2次,我们也不认为是内存泄漏。


4.5、 kmemleak_scan_thread


kmemleak_scan_thread函数实现,整个扫描流程的逻辑见下面流程图:



 

4.6、scan_gray_list


scan_gray_list扫描灰色链表。

 


  • 1、从灰色链表中获取一个object


  • 2、如果object对应的灰色链表不为NULL,则扫描当前的object,扫描完成后,获取下一个object,然后把当前的object从灰色链表中删除,同时递减引用计数,因为在加入灰色链表的时候会调用get_object增加引用计数。


4.7、scan_object


scan_object扫描object的内容。

 


  • 1、如果object的flags中OBJECT_NO_SCAN被置位了,则不去扫描此object对应的内存块。kmemleak_not_leak、kmemleak_ignore等函数会把object的flags置上OBJECT_NO_SCAN,无需扫描此object的内容,可防止误报。


  • 2、如果object已经被释放了,自然也不能扫描。


  • 3、如果object->area_listNULL或者OBJECT_FULL_SCAN被置位,说明object的内存块内容需要被全部扫描。


  • 4、如果object->area_list不为NULL且OBJECT_FULL_SCAN未置位,则扫描object区域的部分内容,只扫描添加到object->area_list中指定的区域(通过kmemleak_scan_area函数指定object内存块的地址扫描范围)。


4.8、scan_block


scan_block扫描指定内存地址范围内容。


 

  • 1、如果扫描的指针不在最大最小值范围内,则跳过此指针。

  • 2、在红黑树中查找是否有满足条件的object,条件为pointer在[object->pointer, object->pointer + size)范围内,如果有则返回对应的object。


  • 3、如果没找到,则跳过此指针。

  • 4、如果pointer指针找到的object是自己,则也跳过此指针。

  • 5、如果已经是灰色的object就不再更新。同时获取object的excess_ref字段,这个字段主要用于vmalloc场景。

  • 6、如果不是灰色的object,则更新object。如果是白色,则对object的count++。如果变成灰色,则增加引用计数同时把object添加到灰色链表中。

  • 7、用于vmalloc场景,通过vm_struct间接访问vmalloc的返回地址。经过扫描发现指针指向的内存块对应的object为vm_struct区域且此object已经变成灰色,则需要检查vm_struct中addr对应的内存块是否在红黑树中,如果在,则需要把addr对应内存块的object的count++。如果变成灰色,则增加引用计数同时把addr对应的object添加到灰色链表中,防止因引用了vm_struct而产生的误报。


5.false positives/negatives


5.1、false positives(误报)


误报不是内存泄漏,而报告为内存泄漏。

可能产生误报的原因:


  • 1、通过固定偏移映射的方式访问虚拟地址。如kasan_module_alloc函数对影子区域的内存块的申请是通过__vmalloc_node_range,而使用是通过非影子区的地址来访问,即通过kasan_mem_to_shadow(addr)函数获取影子区址间接访问。这时候需要通过kmemleak_ignore函数告诉kmemleak这不是内存泄漏。同时kmemleak_ignore还能保证影子区的内容不会被扫描,因为影子区域并不存放指针。


include/linux/kasan.hstatic inline void *kasan_mem_to_shadow(const void *addr){return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)    + KASAN_SHADOW_OFFSET;}


  • 2、没有保存虚拟地址而保存物理地址或者struct page等。


如hsc_msg_alloc函数,保存的是buf对应的page。virt_to_page(buf)


drivers/hsi/clients/hsi_char.cstatic inline struct hsi_msg *hsc_msg_alloc(unsigned int alloc_size)                                                                                                {    void *buf;    buf = kmalloc(alloc_size, GFP_KERNEL);    sg_init_one(msg->sgt.sgl, buf, alloc_size);     /* Ignore false positive, due to sg pointer handling */    kmemleak_ignore(buf);    return msg;}sg_init_onesg_set_buf(sg, buf, buflen)sg_set_page(sg,virt_to_page(buf), buflen,offset_in_page(buf))


  • 3、没有直接保存虚拟地址而是保存虚拟地址或上某个变量。


arch/s390/kernel/nmi.cstatic int __init nmi_init(void){    unsigned long origin, cr0, size;  ...    origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL);                                                                                                 kmemleak_not_leak((void *) origin);  ...    S390_lowcore.mcesad = origin | mcesa_origin_lc;  ...return 0;}


  • 4、指针存放的区域不会被扫描,如vmap函数映射的区域,没有对应的object


kernel/bpf/ringbuf.cstatic struct bpf_ringbuf *bpf_ringbuf_area_alloc({pages = bpf_map_area_alloc(array_size, numa_node);...rb = vmap(pages, nr_meta_pages + 2 * nr_data_pages,      VM_ALLOC | VM_USERMAP, PAGE_KERNEL);kmemleak_not_leak(pages);rb->pages = pages;...}


  • 5、其他情况。


综上可以看出产生误报的原因是没有直接保存申请出来的虚拟地址,而是

保存虚拟地址某种映射关系得到的值,或者存放指针的内存块无法被

扫描(如vmap区域),而产生误报。


如何解决误报?


可以通过kmemleak_ignorekmemleak_not_leak等函数显示告诉kmemleak这不是内存泄漏。kmemleak_ignore表示object不存在内存泄漏,且也不会扫描内存块的内容。kmemleak_not_leak表示object不存在内存泄漏,但是会扫描内存块的内容。


5.2、false negatives(漏报)


漏报是内存泄漏,但是没有报告出来。

比如扫描的地址存放的是数据而不是指针,但是能在红黑树中找到对应的

object,并把此object加入到灰色链表中,这样就产生了漏报。


如何解决漏报?


可以通过kmemleak_ignore、 kmemleak_scan_area kmemleak_no_scan and kmemleak_erase函数解决漏报问题,不同场景使用不同的函数。


6.使用方法


使用kmemleak可以很方便地检测出内核态的内存泄露。可以用于设备驱动程序或内核模块的评估。虽然kmemleak的扫描算法存在漏报和误报的可能,但是并不影响我们的使用。因为这个工具的目的是为了给我们进一步分析提供线索,并不需要绝对精确,小概率的误报和漏报并不影响这个工具的实用性。


6.1、常用功能宏


内容

CONFIG_DEBUG_KMEMLEAK

在kernel hacking中打开CONFIG_DEBUG_KMEMLEAK宏,表示内核支持kmemleak功能。

CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN

如果开启CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN宏,则会触发自动扫描,调用start_scan_thread函数进行扫描。

CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF

如果定义了CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏或者通过cmdline设置为kmemleak=off,则默认关闭kmemleak。如果cmdline中设置kmemleak=on,则表示默认开启kmemleak功能。如果没有定义CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏,则默认是开启kmemleak功能。


6.2、具体使用方法


  • 1、挂载debugfs

mount -t debugfs nodev /sys/kernel/debug/


  • 2、内核线程每10分钟(默认情况下)扫描一次,并打印找到的可疑的内存泄漏object。也可以在任意时刻执行kmemleak的内存扫描。

echo scan > /sys/kernel/debug/kmemleak


  • 3、详细的输出信息通过/sys/kernel/debug/kmemleak获取。

cat /sys/kernel/debug/kmemleak


6.3、其它参数说明


参数

内容

off

禁用kmemleak。不再跟踪内存分配和释放。一旦禁用,就不能再次开启。

stack=on

启用线程栈区域的扫描。默认是on。

stack=off

禁用线程栈区域的扫描。

scan=on

开启kmemleak内核线程的自动扫描。默认为on。

scan=off

停止kmemleak内核线程的自动扫描。

scan=

设置kmemleak线程执行扫描时间间隔。单位为秒,默认为600s(10分钟)。0s表示停止自动扫描。

scan

手动触发扫描,立即扫描。

clear

清除检测出的数据,即清除之前判断为内存泄露的object信息,会把这些object标记为KMEMLEAK_GREY,并不会把object从红黑树和双向链表中删除,不在/sys/kernel/debug/kmemleak中显示,只是不显示,可以使用dump参数进行确定。在使用kmemleak前清除没有关系的信息时使用。

dump=

显示addr对应object信息。


详细的使用方法参考kenrel文档Documentation/dev-tools/kmemleak.rst。


7.案例


从kmemleak.rst文档中摘取的log。


        # cat /sys/kernel/debug/kmemleak        unreferenced object 0xffff89862ca702e8 (size 32):          comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s)          hex dump (first 32 bytes):            6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk            6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.          backtrace:            [<00000000e0a73ec7>] 0xffffffffc01d2036            [<000000000c5d2a46>] do_one_initcall+0x41/0x1df            [<0000000046db7e0a>] do_init_module+0x55/0x200            [<00000000542b9814>] load_module+0x203c/0x2480            [<00000000c2850256>] __do_sys_finit_module+0xba/0xe0            [<000000006564e7ef>] do_syscall_64+0x43/0x110            [<000000007c873fa6>] entry_SYSCALL_64_after_hwframe+0x44/0xa9


通过kmemleak report的输出信息,我们可以获取如下信息:


  • 1、产生泄漏内存块对应的object的起始地址为0xffff89862ca702e8,

泄漏的大小为32个字节。


  • 2、进程名为modprobepid为2088,创建object时的jiffies为375.486s。

  • 3、泄漏内存块的前32字节数据。

  • 4、泄漏点的backtrace信息。

 


Linux阅码场 专业的Linux技术社区和Linux操作系统学习平台,内容涉及Linux内核,Linux内存管理,Linux进程管理,Linux文件系统和IO,Linux性能调优,Linux设备驱动以及Linux虚拟化和云计算等各方各面.
评论
  • 故障现象 一辆2007款日产天籁车,搭载VQ23发动机(气缸编号如图1所示,点火顺序为1-2-3-4-5-6),累计行驶里程约为21万km。车主反映,该车起步加速时偶尔抖动,且行驶中加速无力。 图1 VQ23发动机的气缸编号 故障诊断接车后试车,发动机怠速运转平稳,但只要换挡起步,稍微踩下一点加速踏板,就能感觉到车身明显抖动。用故障检测仪检测,发动机控制模块(ECM)无故障代码存储,且无失火数据流。用虹科Pico汽车示波器测量气缸1点火信号(COP点火信号)和曲轴位置传感器信
    虹科Pico汽车示波器 2025-01-23 10:46 58浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 294浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 150浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 233浏览
  • 随着消费者对汽车驾乘体验的要求不断攀升,汽车照明系统作为确保道路安全、提升驾驶体验以及实现车辆与环境交互的重要组成,日益受到业界的高度重视。近日,2024 DVN(上海)国际汽车照明研讨会圆满落幕。作为照明与传感创新的全球领导者,艾迈斯欧司朗受邀参与主题演讲,并现场展示了其多项前沿技术。本届研讨会汇聚来自全球各地400余名汽车、照明、光源及Tier 2供应商的专业人士及专家共聚一堂。在研讨会第一环节中,艾迈斯欧司朗系统解决方案工程副总裁 Joachim Reill以深厚的专业素养,主持该环节多位
    艾迈斯欧司朗 2025-01-16 20:51 282浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 189浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 186浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 209浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 113浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 117浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 616浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 143浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 418浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 140浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦