当前位置: 首页 > news >正文

mtrace和memleak源码分析

文章目录

    • 1. 内存泄漏
    • 2. 定位工具
      • 2.1 memleak 工具定位内存泄漏
        • 2.1.1 源码解读
      • 2.2 mtrace 工具定位内存泄漏
        • 2.2.1 源码解读

嵌入式内存泄漏定位工具mtrace和memleak源码分析

1. 内存泄漏

内存泄漏(Memory Leak)指程序中已动态分配的堆内存因未正确释放或无法释放,导致系统内存资源被持续占用且无法回收的现象。其核心特征是隐蔽性积累性,可能不会立即引发程序崩溃,但会随着时间推移逐渐消耗系统资源,最终引发性能下降或系统崩溃。

内存泄漏影响如下:

  • 性能下降
    • 内存资源耗尽:内存泄漏会持续占用可用内存,导致程序可用内存减少,频繁触发垃圾回收(GC),增加CPU负担;
    • 内存碎片化:泄漏的内存块可能分散在堆中,导致可用内存被分割为碎片,降低内存分配效率;
  • 系统稳定性受损
    • 程序崩溃:当内存泄漏累积到系统可用内存极限时,可能引发内存溢出(OOM),导致程序强制终止;
    • 资源竞争加剧:泄漏的内存可能影响其他进程或线程的正常运行,导致系统整体响应延迟;

2. 定位工具

内存泄漏,直接的表现就是 free指令会显示剩余内存越来越少,少到一定程度先是会触发SWAP交换,如果SWAP交换后还是内存不足,就会触发OOM现象。

常见的定位工具有vargrindmemleakmtrace,其中嵌入式设备因为内存限制,使用最普遍的是memleakmtrace工具。

2.1 memleak 工具定位内存泄漏

memleak 的原理是利用C语言的宏调用来替代原有的函数调用,如代码中调用malloc(s),实际是调用了dbg_malloc(s),其他的函数类似,如free,calloc都有一个对应的宏替代函数。memleak 工具的本质是内部维护了一个双向链表,用来存储每一次申请的内存地址、大小等信息,free会释放对应链表节点信息。

2.1.1 源码解读
  • 源码下载

    进入sourceforge官网,搜索即可,实际下载网址如下 memleak源码下载

    解压缩得到 memleak-0.3.1 文件夹,有如下文件:

    $ dir
    example.c  LICENSE  Makefile  memleak.c  memleak.h  README
    
    • example.c:meamleak工具的示例说明,演示内存泄漏跟踪的结果;
    • LICENSE:软件的一些说明,如遵循的协议;
    • Makefile:用于编译example.c;
    • memleak.c:相关宏替换接口的实际定义,如dbg_free;
    • memleak.h:相关接口的宏替换声明;
    • README:功能以及更新说明;
  • memleak.h 主要解读

    #define FILE_LINE dbg_file_name = __FILE__, dbg_line_number = __LINE__
    #define malloc(s) (FILE_LINE, dbg_malloc(s))
    #define realloc(p, s) (FILE_LINE, dbg_realloc(p, s))
    #define calloc(n, s) (FILE_LINE, dbg_calloc(n, s))
    #define free(p) (FILE_LINE, dbg_free(p))
    

    从上面可以看到,它将C库的标准函数mallocrealloc callocfree都进行了宏替换,而且还使用了一个逗号表达式来将当前fileline进行赋值,便于后面对链表节点的赋值。

  • memleak.c主要解读
    链表节点定义:

    struct head
    {void *addr;size_t size;char *file;unsigned long line;/* two addresses took the same space as an address and an integer on many archs => usable */union {struct { struct head *prev, *next; } list;struct { char *file; unsigned long line; } free;} in;
    };

    上面定义了一个链表节点结构,可以用来存储本次申请内存的 地址->addr 大小-> size 文件-> file 行数->line ,如果是申请内存,则会存在实用前向指针prev指向前面一次的内存申请节点,后向指针next指向NULL;如果是释放内存,这存储文件名file 和 当前行数line

    static struct head *first = NULL, *last = NULL;#define HLEN sizeof(struct head)static struct head *add(void *buf, size_t s)
    {struct head *p;p = malloc(HLEN);if(p){p->addr = buf;p->size = s;p->file = dbg_file_name;p->line = dbg_line_number;p->in.list.prev = last;p->in.list.next = NULL;if(last)last->in.list.next = p;elsefirst = p;last = p;memory_cnt += s;}return p;
    }void *dbg_malloc(size_t s)
    {void *buf;malloc_cnt++;buf = malloc(s);if(buf){if(add(buf, s))return buf;elsefree(buf);}fprintf(stderr, "%s:%lu: dbg_malloc: not enough memory\n", dbg_file_name, dbg_line_number);return NULL;
    }
    

上面是申请内存完成后,调用add函数,内部申请了一个 head节点保存了申请的地址,大小,申请内存的文件以及行数,然后前向节点指向上一次申请的内存节点last, last的后向节点只向本次申请的内存p,然后p变成了最后一次申请的内存节点last

static void del(struct head *p)
{struct head *prev, *next;prev = p->in.list.prev;next = p->in.list.next;if(prev)prev->in.list.next = next;elsefirst = next;if(next)next->in.list.prev = prev;elselast = prev;memory_cnt -= p->size;/* update history */if(history_length){p->in.free.file = dbg_file_name;p->in.free.line = dbg_line_number;memcpy(histp, p, HLEN);ADVANCE(histp);}free(p);
}static struct head *find_in_heap(void *addr)
{struct head *p;/* start search from lately allocated blocks */ for(p = last; p; p = p->in.list.prev)if(p->addr == addr) return p;return NULL;
}void dbg_free(void *buf)
{struct head *p;free_cnt++;if(buf)if((p = find_in_heap(buf))){del(p);free(buf);}elsedbg_check_addr("dbg_free", buf, CHK_FREED);elsefprintf(stderr, "%s:%lu: dbg_free: NULL\n", dbg_file_name, dbg_line_number);
}

上面在内存释放完成之后,从维护的双向链表中找到对应的free节点信息,然后进行删除链表节点,并删除实际的内存。

void dbg_mem_stat(void)
{fprintf(stderr, "%s:%lu: m: %d, c: %d, r: %d, f: %d, mem: %ld\n",dbg_file_name, dbg_line_number,malloc_cnt, calloc_cnt, realloc_cnt, free_cnt, memory_cnt);
}

上面的函数会把内存申请以及释放的次数进行打印。

void dbg_heap_dump(char *key)
{char *buf;struct head *p;fprintf(stderr, "***** %s:%lu: heap dump start\n", dbg_file_name, dbg_line_number);p = first;while(p){buf = malloc(strlen(p->file) + 2*length(long) + 20);sprintf(buf, "(alloc: %s:%lu size: %lu)\n", p->file, p->line, (unsigned long)p->size);p = p->in.list.next;if(strstr(buf, key)) fputs(buf, stderr);free(buf);}fprintf(stderr, "***** %s:%lu: heap dump end\n", dbg_file_name, dbg_line_number);
}

上面的函数会从漏释放的内存的文件名,行数,以及大小进行打印。

通过上面的源码解读,其实只要在合适的地方使用 dbg_heap_dump 接口就可以统计没有释放的内存的情况了。示例我们在下一篇文章进行讲解。

2.2 mtrace 工具定位内存泄漏

2.2.1 源码解读
  • mtrace 并没有像 memleak一样有单独的源码,GLIBC 开源库本身就支持mtrace功能,mtrace本质是在调用void mtrace (void)接口的时候,内部会为malloc注册tr_mallochook 钩子hook函数,钩子函数注册如下(以下全部以GLIBC2.25版本进行讲解, GLIBC源码下载):

    c函数对应hook函数
    freetr_freehook
    malloctr_mallochook
    calloctr_mallochook
    realloctr_reallochook
    memaligntr_memalignhook
  • 主要源码解读

void
mtrace (void)
{
#ifdef _LIBCstatic int added_atexit_handler;
#endifchar *mallfile;/* Don't panic if we're called more than once.  */if (mallstream != NULL)return;#ifdef _LIBC/* Make sure we close the file descriptor on exec.  */int flags = __fcntl (fileno (mallstream), F_GETFD, 0);if (flags >= 0){flags |= FD_CLOEXEC;__fcntl (fileno (mallstream), F_SETFD, flags);}
#endif/* Be sure it doesn't malloc its buffer!  */malloc_trace_buffer = mtb;setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);fprintf (mallstream, "= Start\n");tr_old_free_hook = __free_hook;__free_hook = tr_freehook;tr_old_malloc_hook = __malloc_hook;__malloc_hook = tr_mallochook;tr_old_realloc_hook =  __realloc_hook;__realloc_hook = tr_reallochook;tr_old_memalign_hook = __memalign_hook;__memalign_hook = tr_memalignhook;
#ifdef _LIBCif (!added_atexit_handler){extern void *__dso_handle __attribute__ ((__weak__));added_atexit_handler = 1;__cxa_atexit ((void (*)(void *))release_libc_mem, NULL,&__dso_handle ? __dso_handle : NULL);}
#endif}elsefree (mtb);}
}     

上面的old系列函数,在初始化的时候都置为了NULL,如下所示,然后使用一个全局的old指针指向这些NULL指针,新的钩子指针函数就指向了上面说的表格里面对应的函数。

static void *
malloc_hook_ini (size_t sz, const void *caller)
{__malloc_hook = NULL;ptmalloc_init ();return __libc_malloc (sz);
}static void *
realloc_hook_ini (void *ptr, size_t sz, const void *caller)
{__malloc_hook = NULL;__realloc_hook = NULL;ptmalloc_init ();return __libc_realloc (ptr, sz);
}static void *
memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
{__memalign_hook = NULL;ptmalloc_init ();return __libc_memalign (alignment, sz);
}void weak_variable (*__free_hook) (void *__ptr,const void *) = NULL;
  • 下面我们以malloc的钩子函数tr_mallochook以及free的钩子函数tr_freehook为例,看一下是如何跟踪内存申请和释放的。

    static __ptr_t
    tr_mallochook (size_t size, const __ptr_t caller)
    {__ptr_t hdr;Dl_info mem;Dl_info *info = lock_and_info (caller, &mem);__malloc_hook = tr_old_malloc_hook;if (tr_old_malloc_hook != NULL)hdr = (__ptr_t) (*tr_old_malloc_hook)(size, caller);elsehdr = (__ptr_t) malloc (size);__malloc_hook = tr_mallochook;tr_where (caller, info);/* We could be printing a NULL here; that's OK.  */fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);__libc_lock_unlock (lock);if (hdr == mallwatch)tr_break ();return hdr;
    }  
    

    上面的第9行,因为tr_old_malloc_hook NULL,所以内存申请走的 第13行,使用的 malloc进行内存申请,malloc函数最终会调用__libc_malloc,此函数内部中因为hook已经被置位为了NULL,所以不会再次调用hook递归,后面就是malloc申请内存的方式了,这部分内容请允许我后面的专题补充,本次只讲解mtrace的跟踪流程。

    strong_alias (__libc_free, __free) strong_alias (__libc_free, free)
    strong_alias (__libc_malloc, __malloc) strong_alias (__libc_malloc, malloc)/* Define ALIASNAME as a strong alias for NAME.  */
    # define strong_alias(name, aliasname) _strong_alias(name, aliasname)
    # define _strong_alias(name, aliasname) \extern __typeof (name) aliasname __attribute__ ((alias (#name)));   
    

    上面的宏定义会使得namealiasname完全等价,也就是我们的malloc等价于__libc_mallocfree等价于__libc_free

    __libc_malloc内容如下:

    void *
    __libc_malloc (size_t bytes)
    {mstate ar_ptr;void *victim;void *(*hook) (size_t, const void *)= atomic_forced_read (__malloc_hook);if (__builtin_expect (hook != NULL, 0))return (*hook)(bytes, RETURN_ADDRESS (0));arena_get (ar_ptr, bytes);victim = _int_malloc (ar_ptr, bytes);/* Retry with another arena only if we were able to find a usable arenabefore.  */if (!victim && ar_ptr != NULL){LIBC_PROBE (memory_malloc_retry, 1, bytes);ar_ptr = arena_get_retry (ar_ptr, bytes);victim = _int_malloc (ar_ptr, bytes);}if (ar_ptr != NULL)__libc_lock_unlock (ar_ptr->mutex);assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||ar_ptr == arena_for_chunk (mem2chunk (victim)));return victim;
    }  
    

    上面的__libc_malloc接口主要调用_int_malloc完成内部分配,具体分配细节我们后面专题讲解。当完成内存分配后,函数会继续跳转到tr_mallochook进行执行。

    重点来了,看重点:

    static __ptr_t
    tr_mallochook (size_t size, const __ptr_t caller)
    {__ptr_t hdr;Dl_info mem;Dl_info *info = lock_and_info (caller, &mem);__malloc_hook = tr_old_malloc_hook;if (tr_old_malloc_hook != NULL)hdr = (__ptr_t) (*tr_old_malloc_hook)(size, caller);elsehdr = (__ptr_t) malloc (size);__malloc_hook = tr_mallochook;tr_where (caller, info);/* We could be printing a NULL here; that's OK.  */fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);__libc_lock_unlock (lock);if (hdr == mallwatch)tr_break ();return hdr;
    } 
    

    上卖弄的第13行完成内存申请,第14行,将hook重新赋值,第18行会把内存申请的信息(地址+大小)进行打印,打印到mallstream文件描述符中。其中mallstream是我们环境变量MALLOC_TRACE实际值得到的,所以我们可以在命令行或者使用setenv函数设置即可改变实际打印的地方。

    上面就是大概申请内存malloc时候的流程了,最终会将申请内存的信息打印到MALLOC_TRACE设置的文件里面。

  • 下面讲一下free的流程,整体上和malloc流程类似

    void
    __libc_free (void *mem)
    {mstate ar_ptr;mchunkptr p;                          /* chunk corresponding to mem */void (*hook) (void *, const void *)= atomic_forced_read (__free_hook);if (__builtin_expect (hook != NULL, 0)){(*hook)(mem, RETURN_ADDRESS (0));return;}if (mem == 0)                              /* free(0) has no effect */return;p = mem2chunk (mem);if (chunk_is_mmapped (p))                       /* release mmapped memory. */{/* See if the dynamic brk/mmap threshold needs adjusting.Dumped fake mmapped chunks do not affect the threshold.  */if (!mp_.no_dyn_threshold&& chunksize_nomask (p) > mp_.mmap_threshold&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX&& !DUMPED_MAIN_ARENA_CHUNK (p)){mp_.mmap_threshold = chunksize (p);mp_.trim_threshold = 2 * mp_.mmap_threshold;LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,mp_.mmap_threshold, mp_.trim_threshold);}munmap_chunk (p);return;} ar_ptr = arena_for_chunk (p);_int_free (ar_ptr, p, 0);
    }    
    

    看见了吧,和上面讲解的__libc_malloc流程几乎类似,先是执行hook,在hook指向的实际函数tr_freehook内部完成记录。然后继续回到__libc_free接口,此接口内部最终使用munmap_chunk完成内存释放。

​ 总结起来就是,调用了mtrace接口后,会为内存申请以及释放接口注册hook,在实际内存申请和释放的时候,hook会先拦截,完成信息的记录,然后继续原有的流程。

  • muntrace 不跟踪接口

    void
    muntrace (void)
    {if (mallstream == NULL)return;/* Do the reverse of what done in mtrace: first reset the hooks andMALLSTREAM, and only after that write the trailer and close thefile.  */FILE *f = mallstream;mallstream = NULL;__free_hook = tr_old_free_hook;__malloc_hook = tr_old_malloc_hook;__realloc_hook = tr_old_realloc_hook;__memalign_hook = tr_old_memalign_hook;fprintf (f, "= End\n");fclose (f);
    }
    

    muntrace接口就是吧mtrace接口内部的相关的hook指针给置位为NULL

    相关的头文件位于#include <mcheck.h>

  • 总结,本次从源码角度大致分支了 memleakmtrace定位内存泄漏的方法:

    • memleak使用的宏代替以及逗号表达式,结合全局的双向循环链表,每申请一次内存,就把信息插入到链表的尾部,每释放一次内存,就从链表中找到对应的节点信息,然后进行节点删除。最后剩余的链表节点就是没有释放的内存。
    • mtrace则是GLIBC内部的一个hook拦截机制,当调用mtrace()接口后,就会将相关的内存操作函数绑定到对应的hook上,每次申请或者释放会在MALLOC_TRACE环境变量指定的文件中进行信息记录。最终使用脚本分析,没有成对出现的地址、大小就是没有释放的内存。

相关文章:

mtrace和memleak源码分析

文章目录 1. 内存泄漏2. 定位工具2.1 memleak 工具定位内存泄漏2.1.1 源码解读 2.2 mtrace 工具定位内存泄漏2.2.1 源码解读 嵌入式内存泄漏定位工具mtrace和memleak源码分析 1. 内存泄漏 内存泄漏&#xff08;Memory Leak&#xff09;指程序中已动态分配的堆内存因未正确释放或…...

Python爬虫技术全解析:从入门到实战的终极指南大纲(深度解读与扩展)

Python爬虫技术全解析&#xff1a;从入门到实战的终极指南大纲&#xff08;深度解读与扩展&#xff09; 文章目录 Python爬虫技术全解析&#xff1a;从入门到实战的终极指南大纲&#xff08;深度解读与扩展&#xff09;前言&#xff1a;数据时代的爬虫使命第一章&#xff1a;Py…...

【网络入侵检测】基于源码分析Suricata的统计模块

【作者主页】只道当时是寻常 【专栏介绍】Suricata入侵检测。专注网络、主机安全,欢迎关注与评论。 1. 概要 👋 在 Suricata 的配置文件中,stats 节点用于配置统计信息相关的参数,它的主要作用是控制 Suricata 如何收集和输出统计数据,帮助用户了解 Suricata 的运行状态和…...

JDBC之Blob类型使用的实现

目录 一、 MySql Blob类型简介 1. Mysql中的Blob类型 2. Blob类型使用的注意事项 二. 插入Blob类型数据 1. 创建表 2. 通过PreparedStatement存储Blob类型数据 三. 解除文件大小限制 四、 读取Blob类型数据 前言 本文来讲解JDBC中的Blob类型 个人主页&#xff1a;艺杯羹…...

truffle

文章目录 truffle目录结构各文件作用在本地测试合约 truffle 项目来自https://github.com/Dapp-Learning-DAO/Dapp-Learning/blob/main/basic/04-web3js-truffle/README-CN.md Truffle 是基于 Solidity 语言的一套开发框架&#xff0c;它简化了去中心化应用&#xff08;Dapp&…...

网盘不限速

引言 哈喽小伙伴们&#xff01;说到网盘下载&#xff0c;是不是感觉心头一紧&#xff1f;特别是像某度那样不开会员就限速到怀疑人生&#xff01;就连之前号称不限速的阿里云盘&#xff0c;现在也是限的死死的。 随着阿里网盘开始限速&#xff0c;很多小伙伴开始转战其他平台。…...

TVM中的Pass两种实现方法?如何选择?

以下是TVM中基于DFPatternCallback和VisitDFPattern两种编写Pass的方法的详细对比与示例总结&#xff1a; 1. 核心概念对比 特性DFPatternCallbackVisitDFPattern (DFPatternFunctor)抽象层级声明式模式匹配命令式访问者模式适用场景简单/中等复杂度的模式匹配需要精细控制匹配…...

JAVA EE_网络原理_UDP与TCP

人海中未遇见时&#xff0c;我将独自前行... ----------陳長生. 1.UDP协议 1.1.UDP协议端格式 UDP&#xff08;用户数据报协议&#xff09;是由 源端口&#xff0c;目标端口&#xff0c;长度&#xff0c;校验和&#xff0c;数据 5种结构组成。16位是UDP报文中字段的长度&#…...

智能Python开发工具PyCharm v2025.1——AI层级功能重磅升级

JetBrains PyCharm是一种Python IDE&#xff0c;其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。此外&#xff0c;该IDE提供了一些高级功能&#xff0c;以用于Django框架下的专业Web开发。 立即获取PyCharm v2025.1正式版 具体更新内容&#xff1a; PyCh…...

15、项目搭建:绘制城堡蓝图——React 19 工程配置

一、魔法结界初始化 1. 召唤项目骨架 npx create-next-applatest hogwarts-castle --ts --tailwind 核心咒语&#xff1a; • --ts&#xff1a;激活预言水晶球&#xff08;TypeScript类型安全&#xff09; • --tailwind&#xff1a;注入飞天扫帚级原子样式&#xff08;…...

docker搭建swarm集群

环境准备 主机名 IP 角色 manger1 192.168.111.47 管理节点 worker1 192.168.111.48 工作节点 worker2 192.168.111.49 工作节点 注&#xff1a;三台主机都已经拉去完swarm和…...

普通IT的股票交易成长史--20250428晚

声明&#xff1a;本文章的内容只是自己学习的总结&#xff0c;不构成投资建议。文中观点基本来自yt站Andylee&#xff0c;美股Alpha姐&#xff0c;综合自己的观点得出。感谢他的无私分享。 仓位就是生命&#xff0c;绝对不能满仓&#xff01;&#xff01;&#xff01;&#xf…...

【React Native】精通 react native

活到老,学到老。 一、基础核心 JavaScript/TypeScript 基础 掌握 ES6+ 语法(箭头函数、解构、Promise、async/await)。熟悉 TypeScript(类型系统、接口、泛型)以提高代码质量。React 核心概念 组件化开发(函数组件、类组件)。状态管理(useState, useEffect, useContex…...

微信小程序-van-uploader的preview-size

preview-size支持数组格式 修改前修改后1、升级微信小程序里面的van版本:2、 重新构建npm3、重启微信开发工具 修改前 引用van组件的上传文件&#xff0c;设置预览图尺寸&#xff0c;刚开始设置的是preview-size“140”&#xff0c;出来的效果就是一个正方形。 修改后 1、升级…...

成员方法的详细说明(结合Oracle官方文档)

在Java的对象创建过程中&#xff0c;成员方法的地址并不存储在对象的堆内存中。Java虚拟机的设计说明&#xff08;包括Oracle的Java虚拟机规范、OpenJDK文档、以及HotSpot的设计文档&#xff09;都明确区分了对象的实例数据&#xff08;存储在堆内存中&#xff09;和类的元数据…...

[蓝桥杯刷题]---模拟法[2]日期问题

题目如下: 题目的意思是&#xff1a; 给出一个日期&#xff08;格式是yy mm dd&#xff0c;注意年份只有两位数&#xff09;&#xff0c;要找出所有可能的真实日期&#xff08;合法的yyyy-mm-dd格式&#xff09;。 需要考虑&#xff1a; 年份范围在1960到2059。 输入的yy、mm、…...

阿里开源图生动画模型AnimateAnyone2

项目背景 近年来&#xff0c;基于扩散模型&#xff08;diffusion models&#xff09;的人物图像动画化方法取得了显著进展&#xff0c;例如 Animate Anyone 在生成一致性和泛化性方面表现优异。然而&#xff0c;这些方法在处理人物与环境之间的空间关系和人-物体交互&#xff0…...

02_使用 AES 算法实现文件加密上传至阿里云、解密下载

02_使用 AES 算法实现文件加密上传至阿里云、解密下载 一、文件上传下载接口 controller 层 RestController RequestMapping("/api/common/file") Api(tags "公共文件上传") AllArgsConstructor Slf4j public class FileV2Controller {private final Os…...

Linux运维——Vim基础

Vim基础 一、移动光标1.1、基础移动1.2、屏幕滚动 二、编辑操作2.1、插入模式2.2、删除与修改2.3、复制粘贴 三、搜索与替换3.1、搜索3.2、替换 4、分屏与窗口管理4.1、分屏操作4.2、窗口调整 五、宏与批量操作六、效率技巧 一、移动光标 1.1、基础移动 快捷键作用h j k l左/…...

从外卖大战看O2O新趋势:上门私厨平台系统架构设计解析

京东高调进军外卖市场&#xff0c;美团全力防守&#xff0c;两大巨头的竞争让整个行业风起云涌。但在这场外卖大战之外&#xff0c;一个更具潜力的细分市场正在悄然兴起——上门私厨服务。 与标准化外卖不同&#xff0c;上门私厨提供的是个性化定制服务。厨师带着新鲜食材上门现…...

【网络编程】ARP协议与主机之间的通信

1. 什么是ARP协议&#xff1f; ARP&#xff08;地址解析协议&#xff0c;Address Resolution Protocol&#xff09; 是一种用于在网络中将IP地址转换为MAC地址的协议。它属于TCP/IP协议栈中的网络层协议&#xff0c;通常在局域网&#xff08;LAN&#xff09;环境下使用&#x…...

JVM模型、GC、OOM定位

JVM模型 程序计数器 程序计数器是一块较小的内存空间&#xff0c;可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令&#xff0c;分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来…...

什么是数据链路层的CRC检测以及为什么要放到帧尾?

数据链路层在封装过程中添加CRC&#xff08;循环冗余校验&#xff09;帧尾&#xff0c;主要目的是为了检测数据传输过程中可能出现的比特错误&#xff0c;确保数据的完整性和可靠性。具体原因如下&#xff1a; 1. 错误检测 物理层传输的不可靠性&#xff1a;数据在物理介质&am…...

Electron 入门指南

Electron 入门指南 Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用的框架。通过 Electron&#xff0c;你可以利用 Web 技术开发出功能强大的桌面应用程序&#xff0c;并且能够运行在 Windows、Mac 和 Linux 系统上。 本文将带你从零开始构建一个简单的 Ele…...

目标检测YOLO实战应用案例100讲- 无人机平台下露天目标检测与计数

目录 知识储备 基于YOLOv8改进的无人机露天目标检测与计数 一、环境配置与依赖安装 二、核心代码实现(带详细注释) 1. 改进YOLOv8模型定义(添加注意力机制) 2. 无人机视角数据增强(drone_augment.py ) 3. 多目标跟踪与计数(tracking_counter.py ) 4. 完整推理流…...

ArkTS基础实验 (二)

任务一&#xff1a;使用模板字符串相关知识&#xff0c;实现多个变量的拼接。同学们可以把自己的姓名、年纪和爱好这三个变量进行拼接。把代码和日志中console.log的打印结果截图保留。 预期效果&#xff1a; 任务二&#xff1a;使用状态变量和点击事件相关知识实现计数器案例…...

【计算机视觉】Bayer Pattern与Demosaic算法详解:从传感器原始数据到彩色图像

Bayer Pattern与Demosaic算法详解&#xff1a;从传感器原始数据到彩色图像 一、引言 在现代数码相机和手机摄像头中&#xff0c;我们能够拍摄到丰富多彩的彩色图像。然而&#xff0c;你可能不知道的是&#xff0c;图像传感器本身并不能直接感知颜色——它们只能感知光的强度。…...

媒体查询使用

一、引言 为了确保网页在不同设备上都能提供良好的用户体验&#xff0c;响应式设计变得至关重要。而媒体查询&#xff08;Media Queries&#xff09;就是前端开发中实现响应式设计的核心技术之一。 二、媒体查询的概念 媒体查询是 CSS3 引入的一项强大功能&#xff0c;它允许开…...

deepseek对IBM MQ SSL 证书算法的建议与解答

在IBM MQ配置SSL TLS的命令中&#xff0c;如果参数SSLCIPH使用TLS_RSA_WITH_AES_128_CBC_SHA256&#xff0c;如下所示&#xff1a; DEFINE CHANNEL(QM1.TO.QM2) CHLTYPE(SDR) TRPTYPE(TCP) CONNAME(QM1.MACH.COM) XMITQ(QM2) SSLCIPH(TLS_RSA_WITH_AES_128_CBC_SHA256) DESCR(S…...

服务器文件同步工具有哪些?

服务器文件同步工具的选择取决于你的具体需求(如实时同步、单向/双向同步、跨平台支持、安全性等)。以下是几款主流的服务器文件同步工具推荐,适用于不同场景: 1. 实时同步工具(适合高频率、低延迟需求) rsync 特点:经典增量同步工具,支持本地/远程同步,高效节省带宽。…...

Numpy数组与矩阵——python学习

我前面提到过Numpy函数&#xff0c;但是不够全&#xff0c;在这里我顺便做一些补充。先说明一下我用的是Notebook。 一、数组的创建与操作 1、把列表转换为数组 np.array([1,2,3,4,5]) 2、把元组转换为数组 np.array((1,2,3,4,5)) 3、把range对象转换为数组 np.array(rang…...

CasaOS上部署1Panel开源运维面板远程在线访问配置实操指南

文章目录 前言1. 添加镜像源2. 部署1Panel3. 本地访问测试4. 安装内网穿透工具5. 配置公网地址6. 配置固定公网地址 前言 很多时候在尝试远程管理服务器时&#xff0c;常常会遇到各种各样的麻烦&#xff0c;尤其是缺乏公网IP或者路由器设置过于复杂时&#xff0c;更是让人感到…...

深入理解缓存淘汰策略:LRU 与 LFU 算法详解及 Java 实现

一、LRU (Least Recently Used - 最近最少使用) LRU 策略的核心思想是&#xff1a;当缓存空间不足时&#xff0c;优先淘汰最近最长时间未被访问的数据。它基于“时间局部性”原理&#xff0c;即最近被访问的数据&#xff0c;在未来被访问的概率也更高。 LeetCode 146. LRU 缓…...

小智项目架构分析

小智代码架构 .github 这就是github项目上拉下来的一些信息 没什么好看的&#xff0c;这跟项目代码无关 .build 编译时生成的文件&#xff0c;没什么可看的&#xff0c;与项目代码无关 .main 主要的代码都在这里面了 .managed_components 这里是小智用到的一些第三方移植…...

基于 SSE 和分块传输的 Uniapp 微信小程序 实现 流式传输 对话

最近的项目是做微信小程序的一个对话框&#xff0c;接入DeepSeek&#xff0c;实现实时对话一个功能。 主要用到的技术点为&#xff1a; 1. Server-Sent Events (SSE) 技术&#xff1a; 在请求头中设置了 ‘X-DashScope-SSE’: ‘enable’&#xff0c;启用了SSE协议 服务器以事…...

[OS] POSIX C库介绍

POSIX C 库可以理解为 Unix/Linux系统的"标准化工具包"&#xff0c;用一句话概括就是&#xff1a; &#x1f449; 它提供了一套跨Unix系统的统一编程接口&#xff0c;让开发者用同一份代码能在不同系统&#xff08;如Linux、macOS&#xff09;中运行。 核心组成&…...

<uniapp><插件><UTS>在uniapp中,创建自己的插件并发布到uni插件市场

前言 本专栏是基于uniapp实现手机端各种小功能的程序&#xff0c;并且基于各种通讯协议如http、websocekt等&#xff0c;实现手机端作为客户端&#xff08;或者是手持机、PDA等&#xff09;&#xff0c;与服务端进行数据通讯的实例开发。 发文平台 CSDN 环境配置 系统&…...

深度学习前沿探秘:Transformer 模型与多领域应用

技术点目录 注意力&#xff08;Attention&#xff09;机制详解自然语言处理&#xff08;NLP&#xff09;领域的Transformer模型详解计算视觉&#xff08;CV&#xff09;领域的Transformer模型详解时间序列建模与预测的大语言模型目标检测算法详解目标检测的大语言模型语义分割的…...

介绍下Nginx的作用与请求转发机制

引言 最近笔者在业务中遇到了Nginx轮训策略使用不当导致后端服务的压力增加&#xff0c;从而导致容器CPU资源不足&#xff0c;响应超时的问题&#xff1b; 但由于对Nginx的了解仅限与作为反向代理使用&#xff0c;所以借用GPT工具整理了Nginx的作用以及请求转发机制&#xff…...

Sql刷题日志(day6)

一、笔试 1、insert ignore&#xff1a;在插入数据时忽略主键冲突或其他唯一性约束冲突。 如果插入的记录会导致主键冲突&#xff08;如 actor_id 已存在&#xff09;&#xff0c;该语句不会报错&#xff0c;而是直接忽略插入操作 语法&#xff1a; INSERT IGNORE INTO tab…...

Ajax 提交表单与文件上传

目录 一、Ajax 提交表单1.1 基本原理1.2 HTML 表单示例1.3 JavaScript 示例(使用 fetch API)二、Ajax 文件上传2.1 基本原理2.2 HTML 文件上传表单示例2.3 JavaScript 示例(使用 fetch API)三、后端处理示例(以 Node.js + Express 为例)3.1 安装依赖3.2 创建服务器文件四…...

【零基础入门】ASP.NET Core快速搭建第一个Web应用

一、为什么选择ASP.NET Core&#xff1f; 跨平台支持&#xff1a;可在Windows/macOS/Linux系统运行 高性能&#xff1a;比传统ASP.NET框架快10倍以上 开源生态&#xff1a;活跃的开发者社区和丰富的NuGet包 云原生支持&#xff1a;完美适配Docker和Kubernetes部署 二、开发…...

盒子模型

1.1看透网页布局的本质 1.2盒子模型的组成部分 css盒子模型本质是一个盒子&#xff0c;封装周围的html元素&#xff0c;它包括边框 外边距 内边距和实际内容。 padding&#xff1a;盒子与内容间的距离margin&#xff1a;盒子与盒子间的距离 1.3border边框 1.border-width 边…...

厚铜PCB如何兼顾质量与成本?供应商设计规范执行的黄金平衡点

厚铜电路板供应商需要遵循一系列设计规范&#xff0c;以确保所提供的电路板符合行业标准和客户要求。以下是一些需要遵循的设计规范&#xff1a; 1. 电路板尺寸和形状&#xff1a;厚铜电路板供应商需要按照客户提供的规格和要求来设计电路板的尺寸和形状。一般来说&#xff0c;…...

Kafka 配置参数性能调优建议

文章目录 1、生产者调优batch.size&#xff08;重要&#xff09;linger.mscompression.typeacks&#xff08;重要&#xff09;buffer.memorymax.in.flight.requests.per.connection&#xff08;重要&#xff09;message.max.bytes&#xff08;重要&#xff09; 2、消费者调优fe…...

Java读Excel:解析阿里云easyExcel导入文件的行号

文章目录 引言I 解析阿里云easyExcel导入文件的行号声明解析对象的基类判断Excel解析对象类型是否包含继承某个类 isAssignableFromJava 转换list类型并设置下标到元素对象属性II 封装excel 文件读取excel 文件读取用法文件导入上下文III 参数校验工具类校验参数是否合法 (jaka…...

Vuex持续保存数据 页面刷新不丢失 vuex-persistedstate

vuex可以进行全局的状态管理&#xff0c;但刷新后刷新后数据会消失&#xff0c;这是我们不愿意看到的。怎么解决呢&#xff0c;我们可以结合本地存储做到数据状态持久化&#xff0c;但是太麻烦每次都要操作&#xff0c;强烈建议使用插件利用vuex-persistedstate插件. 安装 npm …...

.NET8配置组件

一、组件的概念 含义:用于从配置文件中读取配置的组件,叫做配置组件。简单来说, 就是从xml、json、yaml、txt等文件中读取配置的组件。主要采用微软提供的 Microsoft.Extensions.Configuration 二、组件的使用 1、json配置读取 (1)、在Dunk.Common.Project.Configuratio…...

加密算法:ed25519和RSA

ed25519 和 RSA 是两种不同的非对称加密算法,常用于 SSH 密钥认证。以下是它们的对比和选择建议: 1. 算法对比 特性ed25519RSA (4096-bit)安全性更高(基于椭圆曲线密码学 ECC)高(依赖大数分解难度)密钥长度固定 256 位(公钥/私钥更短)通常 2048/4096 位(公钥较大)性能…...

递归、搜索和回溯算法《递归》

在之前的优选算法当中我们已经学习了一些基本的算法&#xff0c;那么接下来我们就要来学习算法当中的一大重要章节——递归、搜索和回溯算法&#xff0c;其实也就是大家常常听到的dfs、bfs&#xff1b;其实本质就是递归&#xff0c;在学习搜索、回溯等算法的过程当中我们会先来…...