linux kernel内存泄漏检测工具之slub debug

news2025/1/11 11:52:19

一、背景

slub debug 是一个debug集,聚焦于kmem_cache 分配机制的slub内存(比如kmalloc),这部分内存在内核中使用最频繁,slub debug其中有相当部分是用来处理内存踩踏,内存use after free 等异常的,由于这部分的检测效果不如kasan(调试时slub前后填充不同的flag,在分配和释放时做检查,存在发现问题不及时的问题), 本文就不介绍了,本文关注slub debug当中的内存泄漏定位方法。

注意:本文中slub和slab名称有些混用,目前linux版本中实际默认都是使用slub,由于内核代码复用的缘故,有很多的函数名,结构体等还是slab命名,是slub还是slab还是以内核config是打开的CONFIG_SLUB还是CONFIG_SLAB来区分,本文所有实验和分析都是基于CONFIG_SLUB=y;

二、SLUB_DEBUG配置及调试工具

2.1 内核中相关配置

CONFIG_SLUB=y
CONFIG_SLUB_DEBUG=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_SLUB_STATS=y
#save the stack
CONFIG_STACKDEPOT=y

2.2 slub_debug命令行参数控制

这个参考 linux-6.6.1/Documentation/mm/slub.rst 描述即可
slub debug相关控制可以通过命令行方式进行:
slub_debug=<Debug-Options>
	打开debug选项,应用到所有的slub类型(具体类型可以参考/proc/slabinfo)

slub_debug=<Debug-Options>,<slab name1>,<slab name2>,...
	打开debug选项,可以选择指定的 slub name, 通过逗号隔开

debug option 当前可以选择调试类型,及开关控制字符

	F		Sanity checks on (SLAB_DEBUG_CONSISTENCY_CHECKS)
	Z		Red zoning(SLAB_RED_ZONE)
	P		Poisoning (object and padding) SLAB_POISON
	U		User tracking (free and alloc) SLAB_STORE_USER
	T		Trace (please only use on single slabs) SLAB_TRACE
	A		Enable failslab filter mark for the cache
	O		Switch debugging off for caches that would have
			caused higher minimum slab orders
	-		关闭所有slub 调试 (useful if the kernel is
			configured with CONFIG_SLUB_DEBUG_ON)

例子: slub 调试只开 sanity checks and red zoning:

	slub_debug=FZ

例子:开启调试,仅针对dentry cache

	slub_debug=,dentry

例子:调试 kmalloc-XXXX和dentry相关slub调试:

	slub_debug=P,kmalloc-*,dentry

例子: 关闭slub debug相关调试(开了CONFIG_SLUB_DEBUG_ON=y才需要)

	slub_debug=-

The state of each debug option for a slab can be found in the respective files
under::

	/sys/kernel/slab/<slab name>/

If the file contains 1, the option is enabled, 0 means disabled. 

slabinfo小工具,内核自带工具,能够方便快速的确认泄漏类型

aarch64-none-linux-gnu-gcc -o slabinfo tools/mm/slabinfo.c

slabinfo 有两个参数指令比较重要:
slabinfo -S      //按slub size占用大小排序slub类型及object个数信息等
slabinfo -T      //打印slub的统计信息

2.3 调试节点

查看slab 使用状态
/proc/slabinfo 
查看slab debug信息,统计状态等
/sys/kernel/slab/*
调试内存泄漏,踩踏等信息
/sys/kernel/debug/slab/*

三、slubdebug原理

3.1 slub 分配基本流程

创建kmem_cache
create_cache    //mm/slab-common.c
   -->struct kmem_cache* s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
   -->__kmem_cache_create(s, flags);
      -->set_cpu_partial(s);
      -->init_kmem_cache_nodes(s)
      -->alloc_kmem_cache_cpus(s)
   -->list_add(&s->list, &slab_caches); //所有的kmem_cache都会加到slab_caches列表中

分配slub
kmem_cache_alloc  mm/slub.c
  -->__kmem_cache_alloc_lru  mm/slub.c
     -->slab_alloc   mm/slub.c
        -->slab_alloc_node mm/slub.c
           -->__slab_alloc_node
               -->object = c->freelist      //(1)如果freelist上有空闲,直接使用本cpu上cpu_slab->slab的
               -->object = __slab_alloc     //否则重新寻找
                   -->slub_percpu_partial   //(2)从cpu_slab->partial上取
                   -->freelist = get_partial(s, node, &pc);  //(3)从node上取         
                   -->slab = new_slab(s, gfpflags, node);    //(4)如果还获取不到,则从buddy中申请内存
                   -->set_track //开启slub debug时启动存储调用栈
  • 获取指定kemem_cache
  • 从percpu变量(struct kmem_cache_cpu*)cpu_slab上获取,从当前cpu cache(cpu_slab->slab)上freelist取
  • 如果cache上用完,则从cpu_slab的partial 列表上提取,并且将该slab 从partial列表删除,并添加到cpu cache上
  • 如果percpu上的cpu_slab上partial列表中用完,则从kmem_cache_node的partial上提取
  • 从page(buddy system)中分配一个struct slab (之前老版本是struct page,当前已经通过filo机制转换)

3.2 slub debug memleak 检测方法

  • 分配slub object时记录trace信息,会根据调用栈生成hash
  • 在每个slub object对应的tack区域存储hash值,记录pid,分配时间等信息
  • 提取分配信息时,扫描所有已分配object的track区域,根据hash值出现次数排序,并利用hash寻找对应的完整调用栈信息,最终排序打印出来

四、测试验证

4.1 测试代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/workqueue.h>
#include <linux/jiffies.h>
#include <asm/page.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>

enum sample_kmemleak_test_case{
    SLAB_LEAK = 0,
    PAGE_LEAK = 1,
    VMALLOC_LEAK = 2,
    PCPU_LEAK = 3,
    SLAB_ALLOC_FREE = 4,
};

static noinline void kmalloc_leak(size_t size, int cnt, bool bfree)
{
    char *ptr;

    int i = 0;
    for (; i < cnt; i++)
    {
        ptr = kmalloc(size, GFP_KERNEL);
        if(bfree)
            kfree(ptr);
    }
}

static noinline void pagealloc_leak(size_t order)
{
    struct page *pages;
    char *ptr;

    pages = alloc_pages(GFP_KERNEL, order);
    ptr = page_address(pages);

    pr_info("%s page addr %llx, page_to_virt %llx\n", __func__, (unsigned long long)pages, (unsigned long long)ptr);
}

static noinline void vmalloc_leak(size_t size)
{
    char *v_ptr;

    v_ptr = vmalloc(size);

    OPTIMIZER_HIDE_VAR(v_ptr);

    pr_info("%s %llx", __func__, (unsigned long long)v_ptr);
    v_ptr[0] = 0;

}

static noinline void sample_kmemleak_test_case(int type, int param)
{
    switch(type) {
        case SLAB_LEAK:
            kmalloc_leak(128, param, false); //alloc 128 byte and repeat param times 
            break;

        case PAGE_LEAK: 
            pagealloc_leak(param);
            break;

        case VMALLOC_LEAK:
            vmalloc_leak(2048);
            break;

        case PCPU_LEAK:
            break;

        case SLAB_ALLOC_FREE:
            kmalloc_leak(128, param, true); //alloc 128 byte and free repeat param times 
            break;

        default :
            pr_info("undef error type %d\n", type);
            break;
    }
    pr_info("%s type %d\n", __func__, type);
}

static noinline ssize_t sample_kmemleak_testcase_write(struct file *filp, const char __user *buf,
                   size_t len, loff_t *off)
{
    char kbuf[64] = {0};
    int ntcase;
    int nparam;
    int ret = 0;
    if(len > 64) {
        len = 64;
    }
    
    if (copy_from_user(kbuf, buf, len) != 0) {
        pr_info("copy the buff failed \n");
        goto done;
    }

    ret = sscanf(kbuf, "%d %d", &ntcase, &nparam);

    if (ret <= 0) {
        pr_err("should enter 2 param, first is test case type, second is param\n");
        goto done;
    }

    sample_kmemleak_test_case(ntcase, nparam);
done:
    return len;
}

static struct file_operations sample_kmemleak_fops = {
    .owner  =   THIS_MODULE,
    .write  =   sample_kmemleak_testcase_write,
    .llseek =   noop_llseek,
};

static struct miscdevice sample_kmemleak_misc = {
    .minor  = MISC_DYNAMIC_MINOR,
    .name   = "sample_kmemleak_test",
    .fops   = &sample_kmemleak_fops,
};

static int __init sample_kmemleak_start(void) 
{
    int ret;

    ret = misc_register(&sample_kmemleak_misc);
    if (ret < 0) {
        printk(KERN_EMERG " sample_kmemleak test register failed %d\n", ret);
        return ret;
    }

    printk(KERN_INFO "sample_kmemleak test register\n");
    return 0;
}

static void __exit sample_kmemleak_end(void) 
{ 
    misc_deregister(&sample_kmemleak_misc);
} 

MODULE_LICENSE("GPL");
MODULE_AUTHOR("geek");
MODULE_DESCRIPTION("A simple kmemleak test driver!");
MODULE_VERSION("0.1");
 
module_init(sample_kmemleak_start);
module_exit(sample_kmemleak_end);

4.2 定位泄漏

加载内存泄漏测试程序
/test # insmod kmemleak_driver.ko 

触发kmalloc 128 泄漏 100000次
/test # echo 0 100000 > /dev/sample_kmemleak_test 


利用工具slabinfo按的size排序查看 slub object,可以查看 space 总占用大小,及objects个数判断泄漏点 为kmalloc-128;
/test # ./slabinfo -S
Name                   Objects Objsize           Space Slabs/Part/Cpu  O/S O %Fr %Ef Flg
kmalloc-128             100331     128           25.6M       3136/1/0   32 1   0  49 U
inode_cache               6649     616            4.7M        290/1/0   23 2   0  86 aU
kernfs_node_cache        23966     128            4.6M       1142/1/0   21 0   0  65 U
dentry                    4041     192            1.0M        127/1/0   32 1   0  74 aU
kmalloc-1k                 384    1024          786.4K         24/0/0   16 3   0  50 U
kmalloc-512                417     512          458.7K         14/2/0   32 3  14  46 U
task_struct                102    3776          425.9K         13/2/0    8 3  15  90 U
kmalloc-2k                  93    2048          393.2K         12/1/0    8 3   8  48 U
kmalloc-4k                  46    4096          393.2K         12/1/0    4 3   8  47 U
radix_tree_node            596     576          393.2K         24/1/0   25 2   4  87 aU
kmalloc-192               1398     192          385.0K         47/1/0   30 1   2  69 U
kmalloc-256                472     256          245.7K         15/1/0   32 2   6  49 U
pool_workqueue             282     512          229.3K         14/1/0   21 2   7  62 U
sighand_cache              102    2080          229.3K          7/2/0   15 3  28  92 AU
biovec-max                  40    4096          196.6K          6/1/0    7 3  16  83 AU

......

如果没有工具,直接通过/proc/slabinfo节点来确认
/test # cat /proc/slabinfo 
slabinfo - version: 2.1
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
......
kmalloc-4k            49     50  12288    2    8 : tunables    0    0    0 : slabdata     25     25      0
kmalloc-2k            94     95   6144    5    8 : tunables    0    0    0 : slabdata     19     19      0
kmalloc-1k           383    390   3072   10    8 : tunables    0    0    0 : slabdata     39     39      0
kmalloc-512          417    441   1536   21    8 : tunables    0    0    0 : slabdata     21     21      0
kmalloc-256          472    483    768   21    4 : tunables    0    0    0 : slabdata     23     23      0
kmalloc-192         1400   1404    296   27    2 : tunables    0    0    0 : slabdata     52     52      0
kmalloc-128       100331 100352    256   32    2 : tunables    0    0    0 : slabdata   3136   3136      0
//这里也可以通过num_objs * objsize的大小排序来确认是kmalloc-128出现泄漏
kmalloc-96           496    540    200   20    1 : tunables    0    0    0 : slabdata     27     27      0
kmalloc-64           877    928    256   32    2 : tunables    0    0    0 : slabdata     29     29      0
kmalloc-32           725    750    160   25    1 : tunables    0    0    0 : slabdata     30     30      0
kmalloc-16           927    928    128   32    1 : tunables    0    0    0 : slabdata     29     29      0
kmalloc-8           1614   1620    112   36    1 : tunables    0    0    0 : slabdata     45     45      0
kmem_cache_node      211    224    256   32    2 : tunables    0    0    0 : slabdata      7      7      0
kmem_cache           211    231    384   21    2 : tunables    0    0    0 : slabdata     11     11      0
......

查看具体的泄漏点
/test # cat /sys/kernel/debug/slab/kmalloc-128/alloc_traces
 100000 kmalloc_leak.constprop.0+0x54/0x80 [kmemleak_driver] age=12920/12945/12972 pid=95 cpus=3
        __kmem_cache_alloc_node+0xf4/0x2a4
        kmalloc_trace+0x20/0x2c
        kmalloc_leak.constprop.0+0x54/0x80 [kmemleak_driver]
        sample_kmemleak_test_case+0x9c/0xa8 [kmemleak_driver]
        sample_kmemleak_testcase_write+0xb0/0x12c [kmemleak_driver]
        vfs_write+0xc8/0x300
        ksys_write+0x74/0x10c
        __arm64_sys_write+0x1c/0x28
        invoke_syscall+0x48/0x110
        el0_svc_common.constprop.0+0x40/0xe0
        do_el0_svc+0x1c/0x28
        el0_svc+0x40/0xe4
        el0t_64_sync_handler+0x120/0x12c
        el0t_64_sync+0x190/0x194

     88 set_kthread_struct+0x38/0xc4 waste=1408/16 age=13270/17638/17797 pid=2 cpus=0-2
        __kmem_cache_alloc_node+0xf4/0x2a4
        kmalloc_trace+0x20/0x2c
        set_kthread_struct+0x38/0xc4
        copy_process+0x7a0/0x145c
        kernel_clone+0x68/0x368
        kernel_thread+0x80/0xb4
        kthreadd+0x144/0x1c4
        ret_from_fork+0x10/0x20
......

五、小结

5.1、性能分析

内存损耗比较大,从slabinfo也可以看到打开slub debug相关的config之后(/proc/slabinfo)下objsize大小变化,未开启时kmalloc-128 objsize就是128,开启debug后变成了384;

5.2 一个标准的slub泄漏定位方法

1、先确认slub存在内存泄漏

启动时记录/proc/meminfo 中SUnreclaim size 大小, 假设此时初始值为A ,然后每半小时或1小时检测SUnreclaim size 大小,假设为B, 如果B - A 增量超过600M 表示存在SUnreclaim 内存泄漏, 这个600M 可以根据实际项目,内存大小来综合设定

2、细化内存泄漏类型

如果版本存在SLUB内存泄漏, 抓取/proc/slabinfo或者使用slabinfo 工具来确认泄漏的slub 类型;

可以使用slabinfo -S 指令,或者直接通过/proc/slabinfo 中<num_objs> <objsize> 这两列信息做一个乘积,在excel 排序一下即可 (注意:这里的size 统计是不区分unreclaim的)

3、开启指定slub 类型泄漏的debug

例子:调试 kmalloc-XXXX和dentry相关slub leak调试:

slub_debug=U,kmalloc-*,dentry

或者全开:slub_debug=U

4、确认泄漏调用栈

等待内存泄漏一段时间后,执行下面即可确认slub泄漏调用栈及泄漏次数(乘上object的size即泄漏大小)

cat /sys/kernel/debug/slab/XXX/alloc_traces

5.3 优化和改进

商用版本上默认可以打开:CONFIG_SLUB_DEBUG=y, 不开CONFIG_SLUB_DEBUG_ON=y(或者参数传递slub_debug开启)对性能是无影响的;

缺陷: 无法开始时默认关闭,出现问题后动态打开,当前只能在发现版本存在slub内存泄漏后可以通过修改启动参数来控制调试开关,再来定位泄漏点;

如果问题复现概率极低,商用版本一直打开slub泄漏检测的话对用户的内存还是有较大影响,一般来说size占用是未开slub debug的2~4倍 。

不能动态开启的原因主要是 kmalloc的object 及size(是否有调试的metadata)在初始化时就确立了,后面无法修改object 和size,或者控制flag开关。

优化方案:当前android厂商针对这种情况也做了一些改进方案;利用vendor hook机制,在一个外部驱动中通过vendor hook机制动态修改kmalloc_caches,及获取 alloc trace即可完成针对kmalloc的动态调试;其核心思想是构建一套开启debug的kmem_cache, 然后替换原始的kmalloc_caches, 后续kmalloc就会走开启debug的kmem_cache,然后就可以定位问题

关键代码(从android kernel 5.15 拷贝,非android的只能仿照下自己加一下注册函数了):
mm/slab_common.c
//kmalloc分配时会根据size大小及flag类型去选择用kmalloc_caches中的哪一个
struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
{
    unsigned int index;
    struct kmem_cache *s = NULL;

    if (size <= 192) {
        if (!size)
            return ZERO_SIZE_PTR;

        index = size_index[size_index_elem(size)];
    } else {
        if (WARN_ON_ONCE(size > KMALLOC_MAX_CACHE_SIZE))
            return NULL;
        index = fls(size - 1);
    }    

    trace_android_vh_kmalloc_slab(index, flags, &s); //1.注册这里vendor hook可以替换掉后面的kmalloc_cache
    if (s)
        return s;

    return kmalloc_caches[kmalloc_type(flags)][index];
}



mm/slub.c中
static void set_track(struct kmem_cache *s, void *object,
            enum track_item alloc, unsigned long addr)
{
    struct track *p = get_track(s, object, alloc);

    if (addr) {
#ifdef CONFIG_STACKTRACE
        unsigned int nr_entries;

        metadata_access_enable();
        nr_entries = stack_trace_save(kasan_reset_tag(p->addrs),
                          TRACK_ADDRS_COUNT, 3);
        metadata_access_disable();

        if (nr_entries < TRACK_ADDRS_COUNT)
            p->addrs[nr_entries] = 0; 
#endif
        p->addr = addr;
        p->cpu = smp_processor_id();
        p->pid = current->pid;
        p->when = jiffies;
        trace_android_vh_save_track_hash(alloc == TRACK_ALLOC, p);  //2.注册这里外部的ko即可获取到调用栈
    } else {
        memset(p, 0, sizeof(struct track));
    }    
}

ko中的实现基本就是将slub.c,slab_common.c中的依赖的结构体,函数等重写一下,注册好上面的两个hook函数,一个替换掉kmalloc_caches, 一个存储slub分配的调用栈,剩下的就是处理好编译报错,将/sys/kernel/debug/slab/XXX/alloc_traces 的实现用在新增的ko中,增加调试节点,即可完成动态开启slubdebug的功能。

参考

极致Linux内核:Linux内存:块分配器slab、slob和slub

SLUB DEBUG原理

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/slub_def.h?h=v6.6.23&id=bb192ed9aa7191a5d65548f82c42b6750d65f569

Linux 内存管理新特性 - Memory folios 解读 | 龙蜥技术

五花肉:内存管理特性分析(七):Linux内核复合页(Compound Page)原理分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1629498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器(Http板块)

【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器&#xff08;Http板块&#xff09; 一、思路图二、Util板块1、Splite板块&#xff08;分词&#xff09;&#xff08;1&#xff09;代码&#xff08;2&#xff09;测试及测试结果i、第一种测试ii、第二种…

PotatoPie 4.0 实验教程(29) —— FPGA实现摄像头图像均值滤波处理

图像的均值滤波简介 图像均值滤波处理是一种常见的图像处理技术&#xff0c;用于降低图像中噪声的影响并平滑图像。该方法通过在图像中滑动一个固定大小的窗口&#xff08;通常是一个正方形或矩形&#xff09;&#xff0c;将窗口中所有像素的值取平均来计算窗口中心像素的新值…

GateWay具体的使用之全链路跟踪TraceId日志

1.创建全局过滤器&#xff0c;在请求头上带入traceId参数&#xff0c;穿透到下游服务. package com.by.filter;import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.jwt.JWTValidator;…

【Kotlin】Channel简介

1 前言 Channel 是一个并发安全的阻塞队列&#xff0c;可以通过 send 函数往队列中塞入数据&#xff0c;通过 receive 函数从队列中取出数据。 当队列被塞满时&#xff0c;send 函数将被挂起&#xff0c;直到队列有空闲缓存&#xff1b;当队列空闲时&#xff0c;receive 函数将…

vue3 vite 路由去中心化(modules文件夹自动导入router)

通过路由去中心化可实现多人写作开发&#xff0c;不怕文件不停修改导致的冲突&#xff0c;modules中的文件可自动导入到index.js中 // 自动导入模块 const files import.meta.globEager(./modules/**.js); const modules {} for (const key in files) {modules[key.replace…

前端工程化Vue使用Node.js设置国内高速npm镜像源(踩坑记录版)

前端工程化Vue使用Node.js设置国内高速npm镜像源&#xff08;踩坑记录版&#xff09; 此篇仅为踩坑记录&#xff0c;并未成功更换高速镜像源&#xff0c;实际解决方法见文末跳转链接。 1.自身源镜像 自身镜像源创建Vue项目下载速度感人 2.更改镜像源 2.1 通过命令行配置 前提…

在Redux Toolkit中使用redux-persist进行状态持久化

在 Redux Toolkit 中使用 redux-persist 持久化插件的步骤如下: 安装依赖 npm install redux-persist配置 persistConfig 在 Redux store 配置文件中(例如 rootReducer.js)&#xff0c;导入必要的模块并配置持久化选项: import { combineReducers } from redux; import { p…

【MySQL关系型数据库】基本命令、配置、连接池

目录 MySQL数据库 第一章 1、什么是数据库 2、数据库分类 3、不同数据库的特点 4、MySQL常见命令&#xff1a; 5、MySQL基本语法 第二章 1、MySQL的常见数据类型 1、数值类型 2、字符类型 3、时间日期类型 2、SQL语句分类 1、DDL&#xff08;数据定义语言&#x…

mysql-sql-练习题-2-窗口函数

窗口函数 访问量max sum建表窗口函数连接 直播间人数 第1、3名建表排名sum 访问量max sum 每个用户截止到每月为止&#xff0c;最大单月访问次数&#xff0c;累计到该月的总访问次数 建表 create table visit(uid1 varchar(5) comment 用户id,month1 varchar(10) comment 月…

28.Gateway-网关过滤器

GatewayFilter是网关中提供的一种过滤器&#xff0c;可以多进入网关的请求和微服务返回的响应做处理。 GatewayFilter(当前路由过滤器&#xff0c;DefaultFilter) spring中提供了31种不同的路由过滤器工厂。 filters针对部分路由的过滤器。 default-filters针对所有路由的默认…

锂电池SOH预测 | 基于BP神经网络的锂电池SOH预测(附matlab完整源码)

锂电池SOH预测 锂电池SOH预测完整代码锂电池SOH预测 锂电池的SOH(状态健康度)预测是一项重要的任务,它可以帮助确定电池的健康状况和剩余寿命,从而优化电池的使用和维护策略。 SOH预测可以通过多种方法实现,其中一些常用的方法包括: 容量衰减法:通过监测电池的容量衰减…

.NET 检测地址/主机/域名是否正常

&#x1f331;PING 地址/主机名/域名 /// <summary>/// PING/// </summary>/// <param name"ip">ip</param>/// <returns></returns>public static bool PingIp(string ip){System.Net.NetworkInformation.Ping p new System.N…

Qt/C++ 波形绘制双缓冲下改善PaintEvent连续绘制卡顿问题(完整代码解析)

音频波形可视化&#xff1a;该控件用于将音频样本数据可视化为波形&#xff0c;常用于音频处理软件中以展示音频信号的时间域特性。 动态数据绘制&#xff1a;控件能够响应外部数据的变化并重新绘制波形&#xff0c;适用于实时或动态的音频数据流。 自定义绘制逻辑&#xff1…

git变更远端仓库名之后如何修改本地仓库配置的另一种方法?(删remote指针、添加、绑定master)

背景 如果某个远端的仓库地址变化后&#xff0c;本地仓库可以修改对应的remote。 之前谈过几种方法&#xff0c;比如重新设置一个新的remote的指针&#xff0c;绑定到新地址。然后删除origin&#xff0c;然后把新指针mv到origin。比如直接seturl修改&#xff08;git remote se…

Apache Seata如何解决TCC 模式的幂等、悬挂和空回滚问题

title: 阿里 Seata 新版本终于解决了 TCC 模式的幂等、悬挂和空回滚问题 author: 朱晋君 keywords: [Seata、TCC、幂等、悬挂、空回滚] description: Seata 在 1.5.1 版本解决了 TCC 模式的幂等、悬挂和空回滚问题&#xff0c;这篇文章主要讲解 Seata 是怎么解决的。 今天来聊一…

容器安全-镜像扫描

前言 容器镜像安全是云原生应用交付安全的重要一环&#xff0c;对上传的容器镜像进行及时安全扫描&#xff0c;并基于扫描结果选择阻断应用部署&#xff0c;可有效降低生产环境漏洞风险。容器安全面临的风险有&#xff1a;镜像风险、镜像仓库风险、编排工具风险&#xff0c;小…

STM32HAL库++ESP8266+cJSON连接阿里云物联网平台

实验使用资源&#xff1a;正点原子F1 USART1&#xff1a;PA9P、A10&#xff08;串口打印调试&#xff09; USART3&#xff1a;PB10、PB11&#xff08;WiFi模块&#xff09; DHT11&#xff1a;PG11&#xff08;采集数据、上报&#xff09; LED0、1&#xff1a;PB5、PE5&#xff…

神经网络的优化器

神经网络的优化器是用于训练神经网络的一类算法&#xff0c;它们的核心目的是通过改变神经网络的权值参数来最小化或最大化一个损失函数。优化器对损失函数的搜索过程对于神经网络性能至关重要。 作用&#xff1a; 参数更新&#xff1a;优化器通过计算损失函数相对于权重参数的…

c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包

介绍 在网络通讯中,Linux系统为每一个socket创建了接收缓冲区与发送缓冲区,对于TCP协议来说,这两个缓冲区是必须的.应用程序在调用send/recv函数时,Linux内核会把数据从应用进程拷贝到socket的发送缓冲区中,应用程序在调用recv/read函数时,内核把接收缓冲区中的数据拷贝到应用…

Xcode 15构建问题

构建时出现的异常&#xff1a; 解决方式&#xff1a; 将ENABLE_USER_SCRIPT_SANDBOXING设为“no”即可&#xff01;