jemalloc 5.3.0的base模块的源码及调用链使用场景的详细分析
一、背景
这篇博客,我们继续之前的 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里对初始化分配逻辑进行分析,已经涉及到了jemalloc 5.3.0里的非常重要的base模块的一部分逻辑,在这篇博客里,我们进一步展开分析base模块,针对的场景也依然是初始化分配逻辑这块来作为切入口。
在第二章里,我们先顺着之前的博客 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 里 3.2.4 里重点提到的malloc_init_hard函数,继续展开分析,在 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 博客里,我们分析了初始化逻辑里的tsd模块的初始化逻辑,在 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里,我们讲到了几个关键概念group、delta、class还有sz.h里几个常用的psz,size,index之间的转换函数及相关含义,有了这两篇的基础,base模块的详细分析相对容易一些。
我们在第二章,我们依然以malloc_init_hard里内存分配逻辑作为切入口,来展开详细分析base模块,对于相关联的概念也会一一进行介绍,在第三章里,我们会用思维导图来汇总一下并附上总结说明。
二、依然以malloc_init_hard里的内存分配逻辑作为切入口,展开详细分析base模块
2.1 base_boot里的2M的分配用的是base_block_alloc函数,是base模块的分配函数
jemalloc 5.3.0的第一次内存分配的地方就是这个malloc_init_hard_a0_locked里的base_boot函数最终调用的base_map进行的2M的分配。
这块我们在之前的博客 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 里已经做了一些介绍,这篇博客里需要再展开分析一下。
base_boot有关的调用链是:
malloc_init_hard->malloc_init_hard_a0_locked->base_boot->base_new->base_block_alloc->base_map
我们先说一下base模块是什么?用来干什么?
2.2 base模块是一个metadata数据的一个分配器
base模块的文件就两个base.h和base.c。
base模块是一个metadata数据的一个分配器。那么什么是metadata数据呢?metadata就是元数据,也就是数据的数据。
base模块只分配元数据的内存,而并不分配malloc的客户所要的内存,也就是说,malloc的使用者所要的内存是由jemalloc里的base分配器以外的其他的底层内存分配器来分配的,这一点我们下面会用堆栈截图来证明。
2.2.1 三个用于分配的base接口都可能会调用到base_block_alloc函数
base模块用于分配的主要接口是三个,base_new函数和base_alloc和base_alloc_edata,其中base_alloc和base_alloc_edata函数,其中base_new用于base的初始化(base本身也是一个元数据),另外两个,则是在指定的base里分配元数据,当然,虽然说在指定的base里分配,但是还是可能按需扩容的,并不是说base_new分配出内存了以后,base_alloc和base_alloc_edata就不会分配新的内存了(关于非base分配器来分配出来的调用链例子在下面 2.4 一节里会讲到)。这三个函数在需要分配新的内存时都会调用base_block_alloc函数,这个函数我们会在后面详细展开描述。
下图是base_new函数调用base_block_alloc函数的截图:
base_alloc和base_alloc_edata,这两个函数都会调用base_alloc_impl:
而base_alloc_impl会在判断出当前空间不够时调用base_extent_alloc进行更多内存的分配:
而base_extent_alloc就会调用base_block_alloc进行内存分配:
2.2.2 分配元数据的base_alloc_edata接口相比base_alloc接口需要在base_alloc_impl时取回sn号,设到base_alloc_edata接口返回的是edata_t指针里去
base_alloc和base_alloc_edata两个函数的主要区别在于base_alloc_edata需要在base_alloc_impl时取回sn号,也就是序列号,并设到新创建的edata_t这个元数据里。
这个sn号是base实例管理的,在base结构初始化时设置成0:
在base_new里创建完元数据后,把上图里的extent_sn_next记录到了base实例里:
base_new里调用base_block_alloc创建元数据时会把传入的表示sn号的指针指向的值加1:
base_block_alloc里调用了base_edata_init函数:
在base_edata_init函数里进行了+1:
你可能会问,这个多出来的sn号有什么用,在下面的 2.7.1 里会讲到。
2.3 base模块分配了哪些元数据?
我们列一下base模块分配的元数据的种类,列出的都是相对重要的元数据,用一次调用栈例子来说明(当然分配的同一种元数据对应的调用栈也可能是不一样的,我们只是举其中的一次调用栈来说明)。
2.3.1 base模块首先会分配base_t实例,也就是base自己这个元数据
上图的堆栈是main之前的第一次malloc的调用,这次malloc的调用我们在之前的博客 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 里也说明了是因为preload的jemalloc库时由于jemalloc的实现里包含了C++的内容,所以需要在main之前的初始化流程里做相关的C++的异常处理用的pool的分配。而上图中的堆栈,是由这一次分配触发,判断出整个jemalloc还未进行初始化,所以调用了malloc_init_hard接口(关于malloc_init_hard接口我们之前的博客里 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 的 3.2.4 分析过一部分),这个函数会间接调用base_boot来初始化第一个base实例,base_boot继而调用了base_new,base_new继而调用了base_block_alloc进行了分配,base_block_alloc使用base_map,base_map调用pages_map,注意,pages_map是base分配器以外的其他jemalloc内存分配器都会用到的一个接口,定义在src/pages.c里,它并不属于base模块。
看base_boot的返回类型就可以体现它分配的就是base_t这个元数据实例:
0是第一个base,第一个base由一个src/base.c里的上截图的static base_t *b0变量来保存的。
2.3.2 base模块会分配提供静态的tcache的tbins信息的cache_bin_info_t数组
cache_bin_info_t数组的首地址定义如下:
它需要动态分配因为其大小不可静态确定。
相关的核心调用代码截图:
可以看到上图里的这次分配大小不大,就82字节,n_reserved_bins是41,41来自于nhbins,因为nhbins比SC_NBINS的值大(SC_NBINS是36):
相关的上下文调用链如下:
2.3.3 base模块会分配管理arena的arena_t的内存
arena是一个内存分配区,不同的线程一般属于不同的arena,默认情况下arena的个数是cpu核心数*4。
base模块分配arena实例的代码逻辑如下:
如上图可以看到一个关于arena实例分配的细节:
arena_t的大小是一个动态值,因为arena_t用了柔性数组:
相关base分配arena的调用链截图:
要注意,这次main之前的这个arena的分配由于分配的空间不大,用之前base分配出来的内存池子里的剩余空间就足够了,所以这次分配并没有触发base_map及底下分配接口。关于从base里挑选可用的空间来进行分配的逻辑,见 2.7 一节。
2.3.4 base模块会分配用来管理实际使用数据内存块的edata_t管理结构
先说明一下edata,它是管理的实际使用的数据内存块,这么说,edata还是一个元数据的数据结构,它管理对应的内存分为两种,一种是用户使用malloc接口触发进行分配的内存,另一种是jemalloc实现的内部逻辑调用泛iallocztm或泛ipallocztm的接口进行内部使用的内存分配。
jemalloc对于不同大小的内存会有不同的策略,对于小size的class,jemalloc会预分配更多块这样的小块,从而组成一个大块的内存块,这个大块的内存块是page size的整数倍。当然对于大size的class,jemalloc就不会预分配这样的内存块了。而edata_t就是管理这样的整块内存块的数据结构。
下图的场景仍然是main之前的在做初始化时的调用栈,下图是在初始化tsd的tcache data的过程中分配各个size class的tcache_bin用的stack_head指针数组的内存时,需要在具体分配该size的内存对应的内存块的分配前(2.4.1 一节的截图流程),先分配该size class的内存块对应的元数据edata数据结构。
上图里的base_alloc_edata所调用base_alloc_impl分配的大小是很小的,如下图:
就128字节:
和 2.3.2 同样的,由于分配的大小很小,所以直接从base里的当前的block块里剩下的内存里扣出一块出来就可以了,它并不会触发base_map及其他底层分配动作。
在启动过程中,关于edata_t管理结构分配的另外一个场景是在tsd_tcache_data_init时在进行分配各个size class的tcache_bin用的stack_head指针数组的内存对应的内存块时,发现通过ehooks_alloc分配出来的一大块extent内存块后有不用的多出来的部分,这部分剩下的内存也需要创建对应的edata管理结构,在创建该剩下的内存的edata管理结构时走到的edata_cache_get再到base_alloc_edata再到base_alloc_impl里,而这个最后三级函数的调用是和刚才说的场景是一致的,在extent_grow_retained函数内到最后三级函数edata_cache_get->base_alloc_edata->base_alloc_impl中间还有两级调用,为extent_split_interior->extent_split_impl,有关完整调用链可见第三章的调用链图。
2.3.5 base模块会分配用来管理关联每个edata信息所需要的radix tree所用到的叶子结构的内存
jemalloc里有个全局唯一的管理关联每个edata信息的radix tree,即jemalloc里的rtree,这个rtree需要用到rtree_leaf_elm_t结构,所需要的该结构体的数量即radix tree的一层一层的数量,这个数量是按照索引项的bit来决定的,一层是18bit,如下图:
所以一层用到了1<<18=26144个,如下图看到rtree_levels里就两层:
这种情况所触发的函数,如下图,是在rtree_leaf_init函数里:
调用链(也是在初始化时场景):
由于这次分配的大小较大:
所以需要通过pages_map来向os要内存:
上图里的pages_map实际做分配的size是在这次分配的调用链里是由base模块里的pind_last变量来管理维护的,每次分配都要+1,因为+1后,得是HUGEPAGE_CEILING进行2M的对齐,所以就变成了分配4M了,有关pind_last的逻辑具体细节可参考之前的博客 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 里 2.2.5 一节。
2.3.6 base模块会分配background线程所用到的background_thread_info_t数据结构
相关的调用截图和调用链截图如下:
2.4 非base分配器分配出内存的调用栈例子
这一节并不是本文的重点,我们并不过多展开,只是把相关调用栈贴出并描述相关调用场景。
这里说的其他分配器,是指离调用os的mmap接口(jemalloc默认只用mmap进行内存分配)进行的内存分配非常近的调用层次的分配函数。jemalloc里pages_map接口封装了这样的os的mmap接口的内存分配,作为一个接口给jemalloc里较底层的分配器所使用。所以,无论是base分配器还是其他的下面会讲到的分配器,最终还是会调用到pages_map接口。
2.4.1 使用extent_alloc_core分配函数
下图调用链是最终用到了extent_alloc_core函数,而extent_alloc_core函数和base_map一样也是调用的extent_alloc_mmap函数,下图调用链所在的场景是在初始化tsd的tcache data的过程中分配各个size class的tcache_bin用的stack_head指针数组的内存对应的内存块,大小在对齐PAGE_SIZE后是32768字节:
上截图也是在初始化流程中,是在 2.3.4 截图流程之后,在 2.3.5 截图的流程之前。
2.4.2 其他调用pages_map的分配器
调用extent_alloc_mmap进行分配的函数就base_map和 2.4.1 说的extent_alloc_core两个。
但是使用pages_map进行分配的函数还有一些,如hpa模块:
hpa_hooks模块:
这里先不展开了。
2.5 base_block_alloc函数有点像分配一个内存池子,每个base都至少有一个内存池子
我们回头来说base_block_alloc函数,上面讲到,base模块里的最终向操作系统去做分配的最终都汇总到了调用这个base_block_alloc函数里。
这个base_block_alloc函数有点像是预分配一个内存池。后面的大大小小的分配都需要在这个池子里进行再分配(只是说这个内存池的管理是按照之前博客说的group delta这样管理的),当然这个池子是可以变大的,但是每一次变大的最小颗粒度很大,之前的博客也说了是至少分配2M,且一次分配比一次分配大,参考之前的 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里的 2.2.5 一节。
刚才说的这个内存池子的分配就是下图里的通过base_block_alloc函数得到的base_block_t:
可以从下图中看到,分配出来的block塞到了base_t结构体里的block链表里(下图是因为是第一个block,所以直接赋值就行了):
如果是新增block,则是下图里的红色框逻辑的逻辑(目前新增block只会被base_extent_alloc函数用到):
因为同一个base实例而言,可以新关联base_block_t,所以就有这一节标题里说的每个base都至少有一个内存池子,意思就是可以有大于一个内存池子。
2.6 base_block_alloc函数分配出来的池子是对应base编号的,且base编号是和arena的编号是一一对应的
1)所谓的base_block_alloc函数分配出来的池子是对应base编号的,意思就是base0至少有一个内存池子,如果有base1的话,那么base1也至少有一个内存池子,如果一个base里发现内存不够,可以新申请一个内存池子再与这个base关联。每笔使用base_block_alloc函数进行的内存分配,都需要明确一个所属的base。
如下图,传入给base_block_alloc函数的unsigned ind就是这个base编号:
0是第一个base,第一个base由一个base.c里的static base_t变量来保存是:
2)刚才说的base编号是和arena的编号一一对应的。下图是代码里能体现逻辑上arena的index对应于base的index的代码细节:
3)顺便提及一个arena的细节,对于大size的内存分配,jemalloc把它归到了最后一个index的arena里,即,如果cpu的数量是20,大内存分配用的是最后一个arena即arena80(假设arena0是第一个)。
这块细节我们在以后的博客里会讲到。
2.7 base里挑选可用的空间来进行分配的逻辑
base里的这个挑选的逻辑就一处,在base_alloc_impl里,这个base_alloc_impl就是上面讲过的两个分配元数据的接口base_alloc和base_alloc_edata必经调用到的。
2.7.1 “挑选”逻辑用到了配对堆 Pairing Heap
在base_alloc_impl里,有下面这段逻辑做所谓的“挑选”:
上图里的红色框出的逻辑里,核心函数edata_heap_remove_first是使用了配对堆的数据结构,如下图看到base的avail数组就是配对堆的数据结构:
base_alloc_impl的实现就是从base里的最多SC_NSIZES个配对堆里:
从最小的可能满足size大小的配对堆往size更大的堆去找,直到遇到非空的配对堆就返回堆里最小的元素。至于如何判断堆里元素谁大谁小,见 2.7.3 一节。
我们先看一下配对堆的宏定义和使用。
2.7.2 配对堆的宏定义和使用
jemalloc里除了base模块里的内存管理以外,数据内存块的管理者edata_cache模块和huge page的管理模块hpdata也使用到了配对堆,所以,配对堆的声明总共有3处,两处在edata.h里,另外一处在hpdata.h里:
其中,base模块用的是edata_heap。
配对堆的定义在各自的.c里,如base模块用到的edata_heap是定义在edata.c里,如下图显示了base模块用到的配对堆关联的配对函数edata_snad_comp:
配对堆的一系列函数的函数名是由大量的宏拼接形成的,如下:
2.7.3 base用到的配对堆如何比较谁大谁小?
我们看一下决定base模块用的配对堆里的元素,决定谁大谁小的逻辑,上一节也说到了,该函数是edata_snad_comp:
可以看到它是先比较edata的sn号,关于edata的sn号,我们在上面的 2.2.2 一节里说到了是如何生成的。
比较完sn号,如果是一样的话,再去比较地址大小。
这么比较是为了让早分配的内存更早被释放,可以减少内存碎片。
2.7.4 base分配时选到的配对堆元素可能大于实际需要的大小,相关的塞回配对堆的逻辑介绍
从上面的 2.7.1 一节里就可以看到,base分配时选到的配对堆元素可能大于实际需要的大小。
我们看一下相关的塞回配对堆的逻辑在哪里,base模块用的是base_extent_bump_alloc_post进行的塞回动作。
下图是base_extent_bump_alloc_post的选择塞哪里的逻辑:
可以看到是用的floor,也就是在塞的时候,会塞到它实际所属的index的下一个,这样在分配时拿到的元素肯定都能满足当前这个delta组里的所有size的情况。关于delta以及group等概念见之前的博客 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 里的 2.2.4 一节。
三、malloc_init_hard时的所有内存分配动作的调用流程图
细心的同学会发现,上面第二章里的所有截图出来的堆栈调用链都是在malloc_init_hard下的函数调用的。
我们把这个期间的所有的内存分配的逻辑调用都在上面一一列出来了,进行了分析。
下面是一张整图,如果需要再看得清楚一些可以参考我发布的资源里的图,资源链接 https://download.csdn.net/download/weixin_42766184/90385037。
相关文章:
jemalloc 5.3.0的base模块的源码及调用链使用场景的详细分析
一、背景 这篇博客,我们继续之前的 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里对初始化分配逻辑进行分析,已经涉及到了jemalloc 5.3.0里的非常重要的base模块的一部分逻辑ÿ…...
Redis 的缓存雪崩、缓存穿透和缓存击穿详解,并提供多种解决方案
本文是对 Redis 知识的补充,在了解了如何搭建多种类型的 Redis 集群,并清楚了 Redis 集群搭建的过程的原理和注意事项之后,就要开始了解在使用 Redis 时可能出现的突发问题和对应的解决方案。 引言:虽然 Redis 是单线程的…...
DevOps工具链概述
1. DevOps工具链概述 1.1 DevOps工具链的定义 DevOps工具链是支持DevOps实践的一系列工具的集合,这些工具覆盖了软件开发的整个生命周期,包括需求管理、开发、测试、部署和运维等各个环节。它旨在通过工具的集成和自动化,打破开发与运维之间…...
开启AI绘画的魔法大门!探索Stable Diffusion的无限魅力~
Stable diffusion介绍: “StableDiffusion是一款创新的AI工具,将原始文本转化为精美图像。用户可调整图像的细节、风格、明暗等参数,创建个性化的高质量图像。这款高效的绘图工具便利了建筑、设计和插画等行业的专业人士,满足了他…...
LVS 负载均衡集群(DR 模式)
一、LVS-DR 模式核心原理 1.1. DR 模式工作原理 LVS-DR(Direct Routing)模式通过 数据链路层(MAC 层) 实现负载均衡,其核心特点是 请求流量经过 Director,响应流量由 Real Server 直接返回客户端…...
pnpm的使用
pnpm的使用 1.安装和使用2.统一包管理工具下载依赖 1.安装和使用 pnpm:performant npm ,意味“高性能的npm”。 pnpm由npm/yarn衍生而来,解决了npm/yarn内部潜在的bug,极大的优化了性能,扩展了使用场景。被誉为“最先进的包管理工具”。 pnpm安装指令: npm i -g p…...
网页五子棋——通用模块
目录 项目创建 通用功能模块 错误码 自定义异常类 CommonResult jackson 加密工具 项目创建 使用 idea 创建 SpringBoot 项目,并引入相关依赖: 配置 MyBatis: 编辑 application.yml: spring:datasource: # 数据库连接配…...
FastAPI 高并发与性能优化
FastAPI 高并发与性能优化 目录 🚀 高并发应用设计原则🧑💻 异步 I/O 优化 Web 服务响应速度⏳ 在 FastAPI 中优化异步任务执行顺序🔒 高并发中的共享资源与线程安全问题 1. 🚀 高并发应用设计原则 在构建高并发应…...
阿里云IOT消息处理
文章主要讲述了阿里云IOT平台如何处理设备上报的消息、如何将消息路由到不同的处理逻辑、如何进行消息转发与转换等操作。 一、接收IOT消息 1.创建订阅 2.案列代码 官网案例代码:如何将AMQP JMS客户端接入物联网平台接收消息_物联网平台(IoT)-阿里云帮助中心 代码…...
缓存三大问题及其解决方案
缓存三大问题及其解决方案 1. 前言 在现代系统架构中,缓存与数据库的结合使用是一种经典的设计模式。为了确保缓存中的数据与数据库中的数据保持一致,通常会给缓存数据设置一个过期时间。当系统接收到用户请求时,首先会访问缓存。如果缓…...
如何在VSCode中免费使用DeepSeek R1:本地大模型编程助手全攻略
目录 一、DeepSeek R1为何值得开发者关注? 1.1 开源的推理王者 1.2 性能实测对比 二、三步搭建本地AI编程环境 2.1 硬件准备指南 2.2 三大部署方案详解 方案一:LM Studio(新手友好) 方案二:Ollama(Docker玩家首选) 方案三:Jan(跨平台利器) 2.3 常见报错解决…...
ECCV2022 | LGV | LGV:利用大几何邻域提升对抗样本的可迁移性
LGV: Boosting Adversarial Example Transferability from Large Geometric Vicinity 摘要-Abstract引言-Introduction实验设置-Experimental SettingsLGV: 源于大几何邻域的迁移性-LGV: Transferability from Large Geometric Vicinity研究LGV特性:损失几何的重要性…...
Git 查看修改记录 二
Git 查看修改记录 二 续接 Git 查看一个文件的修改记录 一 一、修改 A.txt 修改 A.txt number6执行命令 git add . git commit -a -m "修改 number6" # git commit -a -m "修改 number6" 执行 输出如下 # $ git commit -a -m "修改 number6"…...
麒麟操作系统-rabbitmq二进制安装
1、通过官网下载https://www.rabbitmq.com/ 官网网址:https://www.rabbitmq.com 首先下载erlang-23.3.4.11-1.el7.x86_64.rpm,其次下载rabbitmq-server-3.10.0-1.el7.noarch.rpm 2、安装erlang yum install -y erlang-23.3.4.11-1.el7.x86_64.rpm 3、…...
说说平衡树的基本实现,与红黑树的区别是什么
说说平衡树的基本实现,与红黑树的区别是什么 平衡树是一种能够在插入、删除和查找操作中保持平衡的二叉搜索树。其目的是确保树的高度在一定范围内,防止出现极端情况(如链表化),以便提高操作效率。常见的平衡树有 AVL …...
uniapp实现首行首列冻结效果
uniapp首行首列冻结 <template><view class"height800 flex-column absolute bgc-withe"><!-- 第一行 --><view class"flex diy-header"><view class"box">时间</view><scroll-view id"1" ena…...
MySQL单表存多大的数据量比较合适
前言 经常使用MySQL数据库的小伙伴都知道,当单表数据量达到一定的规模以后,查询性能就会显著降低。因此,当单表数据量过大时,我们往往要考虑进行分库分表。那么如何计算单表存储多大的数据量合适?当单表数据达到多大的…...
uniapp 使用 鸿蒙开源字体
uniapp vue3 使用 鸿蒙开源字体 我的需求是全局使用鸿蒙字体。 所以: 0. 首先下载鸿蒙字体: 鸿蒙资源 下载后解压,发现里面有几个文件夹: 字体名称说明Sans默认的鸿蒙字体,支持基本的多语言字符(包括字…...
SiliconCloud 支持deepseek,送2000w token
SiliconCloud SiliconCloud 邀请奖励持续进行,2000 万 Tokens 送不停! 邀请好友赚 2000 万 Tokens:每成功邀请一位新用户通过手机号码注册,您将获得 2000 万 Tokens;注册即送 2000 万 Tokens:受邀好友作为…...
从零开始设计一个完整的网站:HTML、CSS、PHP、MySQL 和 JavaScript 实战教程
前言 本文将从实战角度出发,带你一步步设计一个完整的网站。我们将从 静态网页 开始,然后加入 动态功能(使用 PHP),连接 数据库,最后加入 JavaScript 实现交互功能。通过这个教程,你将掌握一个…...
【Python深入浅出㊸】解锁Python3中的TensorFlow:开启深度学习之旅
目录 一、TensorFlow 简介1.1 定义与背景1.2 特点 二、Python 3 与 TensorFlow 的关系2.1 版本对应2.2 为何选择 Python 3 三、安装 TensorFlow3.1 安装步骤3.2 验证安装 四、TensorFlow 基本概念与使用方法4.1 计算图(Graph)4.2 会话(Sessio…...
CMakeLists使用
1.预定义宏 宏 功能 PROJECT_SOURCE_DIR 使用cmake命令后紧跟的目录,一般是工程的根目录 PROJECT_BINARY_DIR 执行cmake命令的目录 CMAKE_CURRENT_SOURCE_DIR 当前处理的CMakeLists.txt所在的路径…...
P7201 [COCI 2019/2020 #1] Džumbus
题目背景 Marin 是一个心地善良的人,因此他将为他的 N 个朋友组织 Q 次宴会。宴会上唯一的饮料被称为 džumbus。 每位朋友对这种饮料的需求量是已知的。在这些朋友中,有 M 组朋友。每一组中的两位在同时满足他们各自的需求量后,将开始互相核对自己对往届 COCI 题目的答案…...
网络性能测试工具ipref
文章目录 一、ipref的介绍二、iperf安装配置三、iperf使用四、iperf常见故障处理 一、ipref的介绍 ipref是一种常用的网络性能测试工具,用于评估网络带宽、延迟和吞吐量等性能指标。它通过在客户端和服务器之间发送数据流来测量网络的性能,可以帮助管理…...
C# Dictionary的实现原理
在 C# 中,Dictionary<TKey, TValue> 是一个基于哈希表(Hash Table)实现的键值对集合。它提供了高效的插入、删除和查找操作,平均时间复杂度接近 O(1)。下面是 Dictionary 的核心实现原理: 1. Dictionary 的核心数…...
在项目中操作 MySQL
在现代Web开发中,Node.js因其非阻塞I/O模型和高效的性能成为了构建后端服务的热门选择之一。与此同时,MySQL作为最流行的关系型数据库管理系统之一,凭借其稳定性、可靠性和易用性,在数据存储方面扮演着重要角色。本文将详细介绍如…...
第6章 6.4 ASP.NET Core Web API各种技术及选择
6.4.1 控制器父类用哪个 6.2小节和6.3小节所演示的ASP.NET Core Web API 的控制器类都继承自ControllerBase,而6.1中MVC的控制器继承自Controller,Controller又继承自ControllerBase。 所以,一般情况下,编写的WebAPI控制器类继承…...
DeepSeek本地化部署【window下安装】【linux下安装】
一、window 本地安装指导 1.1、下载window安装包 https://ollama.com/download/OllamaSetup.exe 1.2、点击下载好的安装包进行安装 检测安装是否成功: C:\Users\admin>ollama -v ollama version is 0.5.7有上面的输出,则证明已经安装成功。 配置…...
字玩FontPlayer开发笔记14 Vue3实现多边形工具
目录 字玩FontPlayer开发笔记14 Vue3实现多边形工具笔记整体流程临时变量多边形组件数据结构初始化多边形工具mousedown事件mousemove事件监听mouseup事件渲染控件将多边形转换为平滑的钢笔路径 字玩FontPlayer开发笔记14 Vue3实现多边形工具 字玩FontPlayer是笔者开源的一款字…...
kkFileView二开之pdf转图片接口
kkFileView二开之Pdf转图片接口 1 kkFileView源码下载及编译2 Pdf转图片接口2.1 背景2.2 分析2.2 接口开发2.2.1 编写Pdf转图片方法2.2.2 编写转换接口 2.3 接口测试2.3.1 Pdf文件准备2.3.2 pdf2Image 3 部署 1 kkFileView源码下载及编译 前文 【kkFileView二开之源码编译及部…...
达梦tpcc压测
造数 在这个日志输出中,主要执行了一系列数据库操作,涵盖了数据库信息检查、表的创建与数据加载、索引的添加、数据验证等步骤。具体分析如下: 数据库信息检查: 查询了数据库的版本、实例名称、日志文件大小、字符集等信息。 删…...
计算机毕业设计PySpark+hive招聘推荐系统 职位用户画像推荐系统 招聘数据分析 招聘爬虫 数据仓库 Django Vue.js Hadoop
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
DeepSeek正重构人形机器人和具身大模型赛道!
中国人工智能公司DeepSeek(深度求索)以“低成本、高效率、强开放”的研发范式横空出世,火遍并震撼全球科技圈;DeepSeek展现出来的核心竞争力,除了低成本及推理能力,更重要的是开源模型能力追赶上了最新的闭…...
第1章 信息化发展(一)
1.1信息与信息化 1.1.1信息基础 1.信息的定义 信息是物质、能量及其属性的标示的集合,是确定性的增加。它以物质介质为载体,传递和反映世界各种事物存在方式、运动状态等的表征。信息不是物质也不是能量,它以一种普遍形式,表达…...
面试经典150题——字典树
文章目录 1、实现 Trie (前缀树)1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、添加与搜索单词 - 数据结构设计2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、单词搜索 II3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 对于字典树而言,之前做过…...
【前端 DevOps】GitHub Actions 与 GitLab CI 实战:实现前端项目的自动化测试与部署
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
SQLMesh系列教程-3:SQLMesh模型属性详解
SQLMesh 的 MODEL 提供了丰富的属性,用于定义模型的行为、存储、调度、依赖关系等。通过合理配置这些属性,可以构建高效、可维护的数据管道。在 SQLMesh 中,MODEL 是定义数据模型的核心结构,初学SQLMesh,定义模型看到属…...
【Maven】多module项目优雅的实现pom依赖管理
【Maven】多module项目优雅的实现pom依赖管理 【一】方案设计原则【二】项目结构示例【三】实现思路【1】可能的问题点:【2】解决方案的思路:【3】需要注意的地方:【4】可能的错误: 【四】实现案例【1】父POM设计(pare…...
【数字】异步FIFO面试的几个小问题与跨时钟域时序约束
入门数字设计的时候,跨时钟域的数据处理是绕不开的课题,特别是多比特数据跨时钟域时,都会采用异步FIFO的方法。 异步FIFO中涉及较多的考点这里记录几个以供大家参考。 1. 异步FIFO的空满判断分别在哪个域? 根据异步FIFO的结构&…...
云原生时代的开发利器
云原生时代的开发工具集之中,至少应有这样一种利器:基于微服务架构的低代码开发平台,同时与业界标准的云原生技术支撑设施能够完全协同和融合。低代码开发平台的构建不仅仅是采用微服务开发框架,更加重要的是符合当前主流的中台和…...
利用IDEA将Java.class文件反编译为Java文件:原理、实践与深度解析
文章目录 引言:当.class文件遇到源代码缺失第一章:反编译技术基础认知1.1 Java编译执行原理1.2 反编译的本质1.3 法律与道德边界 第二章:IDEA内置反编译工具详解2.1 环境准备2.2 三步完成基础反编译2.3 高级反编译技巧2.3.1 调试模式反编译2.…...
C++ Primer 参数传递
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
2.7 静态方法/构造函数Mock
静态方法/构造函数Mock 在单元测试中,静态方法和构造函数的Mock是相对复杂的需求,因为Mockito的核心设计基于对象实例的模拟。然而,通过扩展工具或特定技巧,可以实现对这些场景的处理。本章详解两种主流方案:PowerMoc…...
注册Gmail如何跳过手机验证环节?
很多小伙伴在注册Gmail的时候都会遇到一个难题:手机号码验证,有可能包括了“手机号无法验证” “国内手机号验证失败” “收不到验证码”等等问题,但 根据真实案例,还有部分人则是“幸运地”没有手机号验证环节,那么今…...
【算法专场】哈希表
目录 前言 哈希表 1. 两数之和 - 力扣(LeetCode) 算法分析 算法代码 面试题 01.02. 判定是否互为字符重排 编辑算法分析 算法代码 217. 存在重复元素 算法分析 算法代码 219. 存在重复元素 II 算法分析 算法代码 解法二 算法代码 算法…...
5、pod 详解 (kubernetes)
pod 详解 (kubernetes) Pod 的基础概念pause 容器Pod 的分类与创建自主式 Pod控制器管理的 Pod静态 Pod Pod容器的分类基础容器(infrastructure container)初始化容器(initcontainers)应用容器(…...
二叉树详解:Java实现与应用
在计算机科学中,数据结构是构建高效算法的基石,而二叉树作为一种基础且重要的树形结构,在诸多领域都有着广泛应用,如数据库索引、文件系统、编译器设计等。本文将从基础概念入手,带你逐步深入理解二叉树,并…...
GPT和BERT
笔记来源: Transformer、GPT、BERT,预训练语言模型的前世今生(目录) - B站-水论文的程序猿 - 博客园 ShusenWang的个人空间-ShusenWang个人主页-哔哩哔哩视频(RNN模型与NLP应用) 一、GPT 1.1 GPT 模型的…...
【工业安全】-CVE-2024-30891- Tenda AC18路由器 命令注入漏洞
1.漏洞描述 2.漏洞复现 2.1 qemu-user 模拟: 2.2 qemu-system模拟: 3.漏洞分析 4.poc代码: 1.漏洞描述 漏洞编号:CVE-2024-30891 漏洞名称:Tenda AC18 命令注入 威胁等级:高危 漏洞详情:Ten…...
如何从0开始将vscode源码编译、运行、打包桌面APP
** 网上关于此的内容很少,今天第二次的完整运行了,按照下文的顺序走不会出什么问题。最重要的就是环境的安装,否则极其容易报错,请参考我的依赖版本以及文末附上的vscode官方指南 ** 第一步:克隆 VSCode 源码 首先…...