Linux库制作与原理:【静态库】【动态库】【目标文件】【ELF文件】【ELF从形成到假造轮廓】【理解链接和加载】
目录
一.什么是库
二.静态库
2.1创建静态库
我们在之前的路径下新建lib使用我们自己的库
2.2 使用makefile生成静态库
三.动态库
3.1动态库生成
3.2动态库使用
3.3库运行搜索路径
四.目标文件
五.ELF文件
六.ELF从形成到加载轮廓
6.1ELF形成可执行
6.2 ELF可执行文件加载
七.理解链接和加载
7.1静态链接
7.2ELF加载与进程地址空间
7.2.1虚拟地址/逻辑地址
7.2.2重新理解进程虚拟地址空间
编辑 7.3动态链接与动态库加载
7.3.1进程如何看到动态库
7.3.2进程间共享库
7.3.3动态链接
7.3.3.1概要
7.3.3.2我们的可执行程序被编译器动了手脚
7.3.3.3动态库中的相对地址
7.3.3.4我们的程序,怎么和库具体映射起来的
7.3.3.5我们的程序,怎么进行库函数调用
7.3.3.6全局偏移量表GOT(global offset table)
7.3.3.7库间依赖
7.3.4总结
一.什么是库
库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:
• 静态库 .a[Linux]、.lib[windows]
• 动态库 .so[Linux]、.dll[windows]
预备代码,第三节:
简单封装的libc库
二.静态库
• 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再 需要静态库。
• 一个可执行程序可能用到许多的库,这些库运行有的是静态库,有的是动态库,而我们的编译默 认为动态链接库,只有在该库下找不到动态.so的时候才会采用同名静态库。我们也可以使用 gcc 的 -static 强转设置链接静态库。
2.1创建静态库
我创建一个目录里面有文件,其中.h里面是声明,.c是方法是实现,usercode.c是我们调用的方法。
我们知道,多文件执行形成.o文件,进行链接后才能使用:
我们不想让别人看到我自己函数的实现,就可以用这种方式发给被人,让别人去链接。
命令:ar
把当前目录的.o文件全部放在libmyc.a文件里。这样就算是打包好了
新开一个目录 ,把我们上面打包好的库和.h文件拿过来
不需要解包,我们在进行链接时需要指明在哪里找库,因为我们的是第三方库,OS只会在系统找,这里我们就需要指明在哪个库,-L .在当前路径,叫做myc的库
我们在之前的路径下新建lib使用我们自己的库
把.h放在lib里的include下,把.o(应该是libmyc.a,写错了)放在lib里的mylib下:
之后放在一个压缩包里
在其他地方就可以直接下载下来:
解压:
解压完毕就是需要形成.o文件,这里需要使用-I选项来表明头文件在哪里:
注意把lib/mylib里面的.o应该是libmyc.a文件,上面弄错了。
下面就是执行的过程:
• -L: 指定库路径
• -I: 指定头文件搜索路径
• -l: 指定库名
• 测试目标文件生成后,静态库删掉,程序照样可以运行
• 关于 -static 选项,稍后介绍
• 库文件名称和引入库的名称:去掉前缀 lib ,去掉后缀 .so , .a ,如: libc.so -> c
2.2 使用makefile生成静态库
• ar 是 gnu 归档工具, rc 表示 (replace and create)
• t: 列出静态库中的文件
• v:verbose 详细信息
三.动态库
• 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
• 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
• 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中, 这个过程称为动态链接(dynamic linking)
• 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
3.1动态库生成
初始文件
生成.o时要用fPIC:
注意动态库和静态库不同,这里不需要用归档工具ar,直接用gcc就行,带上选项-shared:
makefile也就只需要修改一点:
• shared:表示生成共享库格式
• fPIC:产生位置无关码(position independent code)
• 库名规则:libxxx.so
3.2动态库使用
动态库的使用和静态库的使用是一样的:
但是当我运行的时候:
虽然我们在上面的指令中带了选项指明我们的动态库的位置,这个“指明”是给gcc指明。静态库能运行是因为静态库直接在编译时直接链接到可执行文件中的库。而动态库是在运行时才被加载的,即可执行文件依赖于动态库的存在。
这里查看也是not found:
3.3库运行搜索路径
• 拷贝 .so 文件到系统共享库路径下, 一般指 /usr/lib、/usr/local/lib、/lib64 或者开篇指明的库路径等
• 向系统共享库路径下建立同名软连接
• 更改环境变量: LD_LIBRARY_PATH
• ldconfig方案:配置/ etc/ld.so.conf.d/ ,ldconfig更新
第一种比较简单,看第二种:
之后别忘了解除:
第三种是环境变量:
把我们动态库的路径加上去:
这里就有了:
还有第四种,更改系统的配置文件:
在这里面创建一个文件:
往里面写上我们动态库的地址:
但还是找不到:
最后一步重新加载搜索路径:
此时就有了。
结论
四.目标文件
编译和链接这两个步骤,在Windows下被我们的IDE封装的很完美,我们一般都是一键构建非常方便, 但一旦遇到错误的时候呢,尤其是链接相关的错误,很多⼈就束手无策了。
编译的过程其实就是将我们程序的源代码翻译成CPU能够直接运行的机器 代码。 比如:在一个源文件 hello.c 里便简单输出"hello world!",并且调用一个run函数,而这个函数被 定义在另一个原文件 code.c 中。这里我们就可以调用 gcc -c 来分别编译这两个原文件。
在编译之后会生成两个扩展名为 .o 的文件,它们被称作目标文件。要注意的是如果我们修改了一个原文件,那么只需要单独编译它这一个,而不需要浪费时间重新编译整个工程。目标文件是一个二进制的文件,文件的格式是 ELF ,是对二进制代码的一种封装。
五.ELF文件
要理解编译链链接的细节,我们不得不了解一下ELF文件。其实有以下四种文件其实都是ELF文件:
• 可重定位文件(Relocatable File) :即xxx.o⽂件。包含适合于与其他目标文件链接来创建可执行文件或者共享,目标文件的代码和数据。
• 可执行文件(Executable File) :即可执行程序。
• 共享目标文件(Shared Object File) :即 xxx.so文件。
• 内核转储(core dumps) ,存放当前进程的执行上下文,用于dump信号触发。
一个ELF文件由以下四部分组成:
• ELF头(ELF header) :描述文件的主要特性。其位于文件的开始位置,它的主要目的是定位文件的其他部分。
• 程序头表(Program header table) :列举了所有有效的段(segments)和他们的属性。表里记着每个段的开始的位置和位移(offset)、长度,毕竟这些段,都是紧密的放在二进制文件中, 需要段表的描述信息,才能把他们每个段分割开。
• 节头表(Section header table) :包含对节(sections)的描述。
• 节(Section ):ELF文件中的基本组成单位,包含了特定类型的数据。ELF文件的各种信息和 数据都存储在不同的节中,如代码节存储了可执行代码,数据节存储了全局变量和静态数据等。
最常见的节:
• 代码节(.text):用于保存机器指令,是程序的主要执行部分。
• 数据节(.data):保存已初始化的全局变量和局部静态变量。
六.ELF从形成到加载轮廓
6.1ELF形成可执行
• step-1:将多份 C/C++ 源代码,翻译成为目标 .o 文件
• step-2:将多份 .o 文件section进行合并
实际合并是在链接时进行的,但是并不是这么简单的合并,也会涉及对库合并。
6.2 ELF可执行文件加载
• 一个ELF会有多种不同的Section,在加载到内存的时候,也会进行Section合并,形成segment
• 合并原则:相同属性,比如:可读,可写,可执行,需要加载时申请空间等.
• 这样,即便是不同的Section,在加载到内存中,可能会以segment的形式,加载到一起
• 很显然,这个合并工作也已经在形成ELF的时候,合并方式已经确定了,具体合并原则被记录在了 ELF的程序头表(Program header table) 中
下面这个读的是ls命令的section headers
下面是读的 program headers
上面的0-8就是我们可以合并的段,比如.data .bss就合并到一起了。
为什么要将section合并成为segment
• Section合并的主要原因是为了减少页面碎片,提高内存使用效率。如果不进行合并, 假设页面大小为4096字节(磁盘中8个扇区合并后的块大小)(内存块基本大小,加载,管理的基本单位),如果.text部分 为4097字节,.init部分为512字节,那么它们将占用3个页面,而合并后,它们只需2个页面。
• 此外,操作系统在加载程序时,会将具有相同属性的section合并成一个大的 segment,这样就可以实现不同的访问权限,从而优化内存管理和权限访问控制。
对于 程序头表 和 节头表 又有什么用呢,其实ELF 文件提供 2 个不同的视图/视角来让我们理解这 两个部分:
• 链接视图(Linking view) - 对应节头表 Section header table
◦ 文件结构的粒度更细,将文件按功能模块的差异进行划分,静态链接分析的时候一般关注的是链接视图,能够理解 ELF 文件中包含的各个部分的信息。
◦ 为了空间布局上的效率,将来在链接目标文件时,链接器会把很多节(section)合并,规整成可执行的段(segment)、可读写的段、只读段等。合并了后,空间利用率就高了,否则,很小的很小的一段,未来物理内存页浪费太大(物理内存页分配一般都是整数倍一块给你,比如4k),所以,链接器趁着链接就把小块们都合并了。
• 执行视图(execution view) -对应程序头表 Program header table
◦ 告诉操作系统,如何加载可执行文件,完成进程内存的初始化。一个可执行程序的格式中, 一定有 program header table 。
• 说白了就是:一个在链接时作用,一个在运行加载时作用。
从 链接视图 来看:
• 命令 readelf -S hello.o 可以帮助查看ELF文件的 节头表。
• .text节 :是保存了程序代码指令的代码节。
• .data节 :保存了初始化的全局变量和局部静态变量等数据。
• .rodata节 :保存了只读的数据,如一行C语言代码中的字符串。由于.rodata节是只读的,所以只能存在于一个可执行文件的只读段中。因此,只能是在text段(不是data段)中找到.rodata 节。
• .BSS节 :为未初始化的全局变量和局部静态变量预留位置
• .symtab节 : Symbol Table符号表,就是源码里面那些函数名、变量名和代码的对应关系。
• .got.plt节 (全局偏移表-过程链接表):.got节保存了全局偏移表。.got节和.plt节一起提供了对导入的共享库函数的访问入口,由动态链接器在运行时进行修改。对于GOT的理解
◦ 使用 readelf 命令查看 .so 文件可以看到该节。
从 执行视图 来看:
• 告诉操作系统哪些模块可以被加载进内存。
• 加载进内存之后哪些分段是可读可写,哪些分段是只读,哪些分段是可执行的。
我们可以在 ELF头 中找到文件的基本信息,以及可以看到ELF头是如何定位程序头表和节头表的。例 如我们查看下ls的主要信息:
七.理解链接和加载
7.1静态链接
• 无论是自己的.o, 还是静态库中的.o,本质都是把.o文件进行链接的过程
• 所以:研究静态链接,本质就是研究.o是如何链接的
首先一个目录里有,main.exe是两个.o文件链接之后的:
在两个.o文件在进行链接之前,先看一下它们的汇编代码:
• objdump -d 命令:将代码段(.text)进行反汇编查看
• hello.o 中的 main 函数不认识 printf和run 函数
上面可以看出,在每单个的文件中调用函数的e8后面的地址跟的都是全0,其实就是在编译 hello.c 的时候,编译器是完全不知道 printf 和 run 函数的存在的,比如他们位于内存的哪个区块,代码长什么样都是不知道的。因此,编辑器只能将这两个函数的跳转地址先暂 时设为0
查看它们的符号表也是UND未定义:
当它们链接之后,main.s(就有了地址):
查看main.exe的符号表:
最终: 1. 两个.o的代码段合并到了一起,并进行了统一的编址
2. 链接的时候,会修改.o中没有确定的函数地址,在合并完成之后,进行相关call地址,完成代码调用(所以叫做可重定位目标文件!!)
静态链接就是把库中的.o进行合并,和上述过程⼀样
所以链接其实就是将编译之后的所有目标文件连同用到的一些静态库运行时库组合,拼装成一个独立的可执行文件。其中就包括我们之前提到的地址修正,当所有模块组合在一起之后,链接器会根据我们的.o文件或者静态库中的重定位表找到那些需要被重定位的函数全局变量,从而修正它们的地址。这 其实就是静态链接的过程。
7.2ELF加载与进程地址空间
7.2.1虚拟地址/逻辑地址
• 一个ELF程序,在没有被加载到内存的时候,本来就有地址,当代计算机工作的时候,都采用"平坦 模式"进行工作。所以也要求ELF对自己的代码和数据进行统一编址,下面是 objdump -S 反汇编 之后的代码
最左侧的就是ELF的虚拟地址,其实,严格意义上应该叫做逻辑地址(起始地址+偏移量),但是我们 认为起始地址是0.也就是说,其实虚拟地址在我们的程序还没有加载到内存的时候,就已经把可执 行程序进行统一编址了.
• 进程mm_struct、vm_area_struct在进程刚刚创建的时候,初始化数据从哪里来的?从ELF各个 segment来,每个segment有自己的起始地址和自己的长度,用来初始化内核结构中的[start, end] 等范围数据,另外在用详细地址,填充页表.
所以:虚拟地址机制,不光光OS要支持,编译器也要支持.
7.2.2重新理解进程虚拟地址空间
ELF 在被编译好之后,会把自己未来程序的入口地址记录在ELF header的Entry字段中:
EIP存的是起始地址就是上面的Entry字段里面的地址,MMU是页表的起始地址。
7.3动态链接与动态库加载
7.3.1进程如何看到动态库
7.3.2进程间共享库
7.3.3动态链接
7.3.3.1概要
动态链接其实远比静态链接要常用得多。比如我们查看下 main.exe 这个可执行程序依赖的动态库,会发现它就用到了一个c动态链接库:
这里的libc.so是C语言的运行时库,里面提供了常用的标准输入输出文件字符串处理等等这些功能。
那为什么编译器默认不使用静态链接呢?静态链接会将编译产生的所有目标⽂件,连同用到的各种 库,合并形成一个独立的可执行文件,它不需要额外的依赖就可以运行。照理来说应该更加方便才对是吧?
静态链接最大的问题在于生成的文件体积大,并且相当耗费内存资源。随着软件复杂度的提升,我们的操作系统也越来越臃肿,不同的软件就有可能都包含了相同的功能和代码,显然会浪费大量的硬盘空间。
这个时候,动态链接的优势就体现出来了,我们可以将需要共享的代码单独提取出来,保存成⼀个独立的动态链接库,等到程序运行的时候再将它们加载到内存,这样不但可以节省空间,因为同一个模块在内存中只需要保留一份副本,可以被不同的进程所共享。
动态链接到底是如何工作的?? 首先要交代一个结论,动态链接实际上将链接的整个过程推迟到了程序加载的时候。比如我们去运行一个程序,操作系统会首先将程序的数据代码连同它用到的一系列动态库先加载到内存,其中每个动态库的加载地址都是不固定的,操作系统会根据当前地址空间的使用情况为它们动态分配一段内存。 当动态库被加载到内存以后,一旦它的内存地址被确定,我们就可以去修正动态库中的那些函数跳转 地址了。
7.3.3.2我们的可执行程序被编译器动了手脚
在C/C++程序中,当程序开始执行时,它首先并不会直接跳转到 main 函数。实际上,程序的入口点是 _start ,这是一个由C运行时库(通常是glibc)或链接器(如ld)提供的特殊函数。
在 _start 函数中,会执行一系列初始化操作,这些操作包括:
1. 设置堆栈:为程序创建一个初始的堆栈环境。
2. 初始化数据段:将程序的数据段(如全局变量和静态变量)从初始化数据段复制到相应的内存位 置,并清零未初始化的数据段。
3. 动态链接:这是关键的一步, _start 函数会调用动态链接器的代码来解析和加载程序所依赖的 动态库(shared libraries)。动态链接器会处理所有的符号解析和重定位,确保程序中的函数调 用和变量访问能够正确地映射到动态库中的实际地址。
动态链接器:
◦ 动态链接器(如ld-linux.so)负责在程序运行时加载动态库。
◦ 当程序启动时,动态链接器会解析程序中的动态库依赖,并加载这些库到内存中。
环境变量和配置文件:
◦ Linux系统通过环境变量(如LD_LIBRARY_PATH)和配置文件(如/etc/ld.so.conf及其子配置文件)来指定动态库的搜索路径。
◦ 这些路径会被动态链接器在加载动态库时搜索。
缓存文件:
◦ 为了提高动态库的加载效率,Linux系统会维护一个名为/etc/ld.so.cache的缓存文件。
◦ 该文件包含了系统中所有已知动态库的路径和相关信息,动态链接器在加载动态库时会首先搜索这个缓存文件。
4. 调用 __libc_start_main :一旦动态链接完成, _start 函数会调用 __libc_start_main (这是glibc提供的一个函数)。 __libc_start_main 函数负责执行一些额外的初始化工作,比如设置信号处理函数、初始化线程库(如果使用了线程)等。
5. 调用 main 函数:最后, __libc_start_main 函数会调用程序的 main 函数,此时程序的执行控制权才正式交给用户编写的代码。
6. 处理 main 函数的返回值:当 main 函数返回时, __libc_start_main 会负责处理这个返回 值,并最终调用_exit 函数来终止程序(退出码)。
7.3.3.3动态库中的相对地址
动态库为了随时进行加载,为了支持并映射到任意进程的任意位置,对动态库中的方法,统一编址, 采用相对编址的方案进行编制的(其实可执行程序也一样,都要遵守平坦模式,只不过exe是直接加载的)。
7.3.3.4我们的程序,怎么和库具体映射起来的
• 动态库也是一个文件,要访问也是要被先加载,要加载也是要被打开的
• 让我们的进程找到动态库的本质:也是文件操作,不过我们访问库函数,通过虚拟地址进行跳转访问的,所以需要把动态库映射到进程的地址空间中
7.3.3.5我们的程序,怎么进行库函数调用
• 库已经被我们映射到了当前进程的地址空间中
• 库的虚拟起始地址我们也已经知道了
• 库中每一个方法的偏移量地址我们也知道
• 所以:访问库中任意方法,只需要知道库的起始虚拟地址+方法偏移量即可定位库中的方法
• 而且:整个调用过程,是从代码区跳转到共享区,调用完毕在返回到代码区,整个过程完 全在进程地址空间中进行的.
7.3.3.6全局偏移量表GOT(global offset table)
• 也就是说,我们的程序运行之前,先把所有库加载并映射,所有库的起始虚拟地址都应该提前知道
• 然后对我们加载到内存中的程序的库函数调用进行地址修改,在内存中二次完成地址设置 (这个叫做加载地址重定位)
• 等等,修改的是代码区?不是说代码区在进程中是只读的吗?怎么修改?能修改吗?
所以:动态链接采用的做法是在 .data (可执行程序或者库自己)中专门预留一片区域来存放函数 的跳转地址,它也被叫做全局偏移表GOT,表中每一项都是本运行模块要引用的一个全局变量或函数的地址。
• 因为.data区域是可读写的,所以可以支持动态进行修改
# .got在加载的时候,会和.data合并成为一个segment,然后加载在一起
1. 由于代码段只读,我们不能直接修改代码段。但有了GOT表,代码便可以被所有进程共享。但在不同进程的地址空间中,各动态库的绝对地址、相对位置都不同。反映到GOT表上,就是每个进程的每个动态库都有独立的GOT表,所以进程间不能共享GOT表。
2. 在单个.so下,由于GOT表与 .text 的相对位置是固定的,我们完全可以利用CPU的相对寻址来找到GOT表。
3. 在调用函数的时候会首先查表,然后根据表中的地址来进行跳转,这些地址在动态库加载的时候会被修改为真正的地址。
4. 这种方式实现的动态链接就被叫做 PIC 地址无关代码 。换句话说,我们的动态库不需要做任何修改,被加载到任意内存地址都能够正常运行,并且能够被所有进程共享,这也是为什么之前我们给编译器指定-fPIC参数的原因,PIC=相对编址+GOT。
7.3.3.7库间依赖
plt是什么
• 不仅仅有可执行程序调用库
• 库也会调用其他库!!库之间是有依赖的,如何做到库和库之间互相调用也是与地址无关的呢??
• 库中也有.GOT,和可执行一样!这也就是为什么大家为什么都是ELF的格式!
• 由于动态链接在程序加载的时候需要对大量函数进行重定位,这一步显然是非常耗时的。为了进一步降低开销,我们的操作系统还做了一些其他的优化,比如延迟绑定,或者也叫PLT(过程连接表 (Procedure Linkage Table))。与其在程序一开始就对所有函数进行重定位,不如将这个过程推迟到函数第一次被调用的时候,因为绝大多数动态库中的函数可能在程序运行期间一次都不会被使用到。
思路是:GOT中的跳转地址默认会指向一段辅助代码,它也被叫做桩代码/stup。在我们第一次调用函数的时候,这段代码会负责查询真正函数的跳转地址,并且去更新GOT表。于是我们再次调用函数的时候,就会直接跳转到动态库中真正的函数实现。
总而言之,动态链接实际上将链接的整个过程,比如符号查询、地址的重定位从编译时推迟到了程序的运行时,它虽然牺牲了一定的性能和程序加载时间,但绝对是物有所值的。因为动态链接能够更有效的利用磁盘空间和内存资源,以极大方便了代码的更新和维护,更关键的是,它实现了二进制级别的代码复用。
7.3.4总结
• 静态链接的出现,提高了程序的模块化水平。对于一个大的项目,不同的人可以独立地测试和开发自己的模块。通过静态链接,生成最终的可执行文件。
• 我们知道静态链接会将编译产生的所有目标文件,和用到的各种库合并成一个独立的可执行文件, 其中我们会去修正模块间函数的跳转地址,也被叫做编译重定位(也叫做静态重定位)。
• 而动态链接实际上将链接的整个过程推迟到了程序加载的时候。比如我们去运行一个程序,操作系统会首先将程序的数据代码连同它用到的一系列动态库先加载到内存,其中每个动态库的加载地址都是不固定的,但是无论加载到什么地方,都要映射到进程对应的地址空间,然后通过.GOT方式进行调用(运行重定位,也叫做动态地址重定位)。
相关文章:
Linux库制作与原理:【静态库】【动态库】【目标文件】【ELF文件】【ELF从形成到假造轮廓】【理解链接和加载】
目录 一.什么是库 二.静态库 2.1创建静态库 我们在之前的路径下新建lib使用我们自己的库 2.2 使用makefile生成静态库 三.动态库 3.1动态库生成 3.2动态库使用 3.3库运行搜索路径 四.目标文件 五.ELF文件 六.ELF从形成到加载轮廓 6.1ELF形成可执行 6.2 ELF可执行文…...
中间件-redis-(ubantu)
1、安装依赖包 sudo apt-get update sudo apt-get install redis 一旦安装完成,Redis 服务将会自动启动。想要检查服务的状态,输入下面的命令: rootvims:/etc/redis# sudo systemctl status redis-server ● redis-server.service - Adva…...
ubuntu20.04+ROS+Gazebo+px4+QGC+MAVROS
目录 前言 一、安装ROS 二、安装PX4 编译 三、QGC安装 四、安装MAVROS 命令记得加sudo! 前言 在安装ubuntu20.04ROSGazebopx4QGCMAVROS时,参考了很多网上的资料,总结一个较为顺利的流程。 官方指南PX4 自动驾驶仪用户指南 | PX4 Gui…...
基于 openEuler 构建 LVS-DR 群集(同网段)。
一、LVS相关原理 1.LVS简介 LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项 目,它的官方站点是www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分,在 Linux2.4内核以前&…...
计算机毕业设计PySpark+Hadoop+Hive机票预测 飞机票航班数据分析可视化大屏 航班预测系统 机票爬虫 飞机票推荐系统 大数据毕业设计
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
【设计模式】【行为型模式】观察者模式(Observer)
👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 📫 欢迎V: flzjcsg2,我们共同讨论Java深渊的奥秘 …...
机器学习: 逻辑回归
概念与定义 逻辑回归是一种用于分类问题的统计方法。它通过计算目标变量的概率来预测类别归属,并假设数据服从伯努利分布(二分类)或多项式分布(多分类)。逻辑回归模型输出的是概率值,通常使用sigmoid函数将线性组合映射到0和1之间。 1. 概念 逻辑回归用于解决分类问题…...
域名解析—互联网世界的导航系统
在互联网的世界里,每个网站都像一座“城市”,而用户要找到这些“城市”,必须依赖一套精准的导航系统——这就是域名解析。无论是浏览网页、发送邮件,还是使用移动应用,域名解析都在背后默默支撑着用户的每一次访问。本…...
PAT乙级真题 — 1080 MOOC期终成绩(java)【测试点3超时】
对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,必须首先获得不少于200分的在线编程作业分,然后总评获得不少于60分(满分100)。总评成绩的计…...
【Prometheus】如何通过prometheus监控redis实时运行状态,并实现告警通知
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
ARM Cortex-M3/M4 权威指南 笔记【一】技术综述
一、Cortex-M3/M4 处理器的一般信息 1.1 处理器类型 ARM Cortex-M 为 32 位 RISC(精简指令集)处理器,其具有: 32位寄存器32位内部数据通路32位总线接口 除了 32 位数据,Cortex-M 处理器(以及其他任何 A…...
【Qt】定期清理程序
在现有Qt程序中实现可配置日志保存天数的代码示例,分为界面修改、配置存储和核心逻辑三部分: // 1. 在配置文件(如settings.h)中添加保存天数的配置项 class Settings { public:int logRetentionDays() const {return m_settings…...
基于51单片机的门禁刷卡器proteus仿真
地址:https://pan.baidu.com/s/1j0KAmH5pVGWZWRpT6p5hBg 提取码:1234 仿真图: 芯片/模块的特点: AT89C52/AT89C51简介: AT89C52/AT89C51是一款经典的8位单片机,是意法半导体(STMicroelectron…...
二、数据持久化篇(深度增强版)
二、数据持久化篇(深度增强版) 2.1 JDBC Template深度解析 架构设计思想 #mermaid-svg-y2IrKiVu2gzenoCB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-y2IrKiVu2gzenoCB .error-icon{fil…...
时间敏感和非时间敏感流量的性能保证配置
论文标题 中文标题: 时间敏感和非时间敏感流量的性能保证配置 英文标题: Provisioning of Time-Sensitive and non-Time-Sensitive Flows with Assured Performance 作者信息 Luis Velasco, Gianluca Graziadei, Sima Barzegar, Marc Ruiz Optical Co…...
k8s管理工具之lens
什么是lens Lens 是当前市场上最强大的K8S IDE。它是一个独立的单机应用,可以同时运行在macOS、Windows和Linux上。 作为K8S IDE,该有的它基本都有了! 集群管理 导入已有集群 首先,你需要在 Lens 中添加你的 Kubernetes 集群。点…...
kafka介绍,kafka集群环境搭建,kafka命令测试,C++实现kafka客户端
目录 kafka介绍kafka集群环境搭建zookeeper安装与配置kafka安装与配置 kafka命令测试C实现kafka客户端librdkafka库编译新版本cmake编译cppkafka库编译C实现kafka生产者和消费者客户端 kafka介绍 定义与概述 Apache Kafka 是一个开源的分布式流处理平台,最初由 Lin…...
DeepSeek的蒸馏技术:让模型推理更快
DeepSeek系列模型,如DeepSeek-R1-Distill-Qwen-7B,采用了知识蒸馏(Knowledge Distillation)技术,这是一种强大的模型压缩和优化方法。通过蒸馏,DeepSeek模型在保持甚至提升性能的同时,实现了更快…...
SAP-ABAP:dialog界面中的数据块Event Block详解举例
在SAP的Dialog程序开发中,Event Block(事件块)是屏幕流逻辑(Flow Logic)中的关键部分,用于定义屏幕在特定事件触发时执行的逻辑。Event Block通常与ABAP模块(Module)结合使用&#x…...
微信小程序 - 模版语法
声明和绑定数据 小程序页面中使用的数据均需要在 Page() 方法的 data 对象中进行声明定义 在将数据声明好以后,需要在 WXML 中绑定数据,数据绑定最简单的方式是使用 Mustache 语法(双大括号)将变量包起来。 在 {{ }} 内部可以做…...
mapbox进阶,添加绘图扩展插件,裁剪线
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…...
Dav_笔记14:优化程序提示 HINTs -2
优化方法和目标的提示 ALL_ROWS和FIRST_ROWS(n)提示允许您在优化方法和目标之间进行选择。如果SQL语句具有指定优化方法和目标的提示,则优化程序将使用指定的方法,无论是否存在统计信息,OPTIMIZER_MODE初始化参数的值…...
Oracle ORA-00054
ORA-00054: resource busy and acquire with NOWAlT specified or timeout expire 错误 ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 是 Oracle 数据库中常见的一个错误,通常发生在尝试获取一个已经被其他会话占用的资源时。这…...
ABB能源自动化选用宏集Cogent DataHub避免DCOM问题,实现高效、安全的数据传输
案例概况 ABB能源自动化公司通过宏集Cogent DataHub软件将电厂设施的数据实时传输到公司办公室,实现了OPC隧道/镜像解决方案,在电厂和公司网络之间建立了一个安全、可靠的连接,确保数据传输的高度安全,减少入侵风险。 ࿰…...
IP地址有哪些类型?
IP地址是计算机网络中用来识别和查找设备的唯一标识符。根据其作用和使用范围,IP地址可分为以下几种类型: 1.局域网IP地址 局域网IP地址又称内网IP地址,是局域网内用来识别和查找局域网设备的地址。局域网是一个相对较小的网络,…...
网络安全评估:保障设备与系统安全的关键
保障网络安全离不开对入网设备的安全评估,这种评估运用了多种技术和手段,对网络中的设备与系统进行详尽的检查。它能迅速发现并排除潜在的安全风险,对网络系统的安全稳定运行具有极其关键的作用。 测评目的 确保网络系统的安全与稳定是网络…...
一竞技瓦拉几亚S4预选:YB 2-0击败GG
在2月11号进行的PGL瓦拉几亚S4西欧区预选赛上,留在欧洲训练的YB战队以2-0击败GG战队晋级下一轮。双方对阵第二局:对线期YB就打出了优势,中期依靠卡尔带队进攻不断扩大经济优势,最终轻松碾压拿下比赛胜利,以下是对决战报。 YB战队在天辉。阵容是潮汐、卡尔、沙王、隐刺、发条。G…...
管式超滤膜分离技术在茶澄清浓缩领域的创新应用
管式超滤膜分离技术在茶澄清浓缩领域展现出广阔的前景,其独特优势和应用效果正逐渐改变着茶饮料行业的生产方式。以下是几个关键点,说明了这一技术为何具有如此积极的发展潜力: 1. 高效澄清与保留风味 管式超滤膜具有高精度的过滤能力&#x…...
maven web项目如何定义filter
在 Maven Web 项目中定义一个 Servlet 过滤器(Filter),需要遵循 Java Servlet 规范,并利用 Maven 来管理项目结构和依赖。下面是如何在 Maven Web 项目中定义和配置一个过滤器的基本步骤: 1. 创建过滤器类 首先&…...
如何在MacOS上查看edge/chrome的扩展源码
步骤 进入管理扩展页面点击详细信息复制对应id在命令行键入 open ~/Library/Application Support/Microsoft Edge/Default/Extensions/${你刚刚复制的id} 即可打开访达中对应的更目录 注意 由于原生命令行无法直接处理空格 ,所以需要加转义符\,即:open ~/Librar…...
【学术投稿-2025年计算机视觉研究进展与应用国际学术会议 (ACVRA 2025)】CSS样式解析:行内、内部与外部样式的区别与优先级分析
简介 2025年计算机视觉研究进展与应用(ACVRA 2025)将于2025年2月28-3月2日在中国广州召开,会议将汇聚世界各地的顶尖学者、研究人员和行业专家,聚焦计算机视觉领域的最新研究动态与应用成就。本次会议将探讨前沿技术,…...
redis记录用户在线状态+活跃度
1.记录用户在线状态 redis的Bitmap记录用户在线状态 使用一个大的Bitmap,每个bit位对应一个用户IDbit值1表示在线,0表示离线用户ID与bit位的映射关系: bit位置 用户ID % bitmap容量 具体实现: # 用户上线时,设置对应bit为1 SETBIT online_users {user_id} 1# 用户下线时,设…...
vmware安装win7
1、版本说明 vmware workstation 16 win7 X64 2、安装步骤 安装步骤有点独特,先配置虚拟机,然后再虚拟机的虚拟光驱里添加下载的win7。 配置完了之后,点击要运行的虚拟机,然后一直往下走就可以完成系统的安装。 3、配置系统以解…...
OpenAI推出的Computer Use智能体:Operator是什么
OpenAI推出的Computer Use智能体:Operator是什么 是一款能像人一样与图形用户界面交互来操作计算机的AI智能体。以下是其核心原理及举例说明: 核心原理 感知: 屏幕截图获取:利用高性能屏幕捕获模块,如基于WebRTC的截图技术,以极低延迟获取高清晰度页面图像,为后续分析…...
[FastAdmin] 上传图片并加水印,压缩图片
1.app\common\library\Upload.php 文件 upload方法 /*** 普通上传* return \app\common\model\attachment|\think\Model* throws UploadException*/public function upload($savekey null){if (empty($this->file)) {throw new UploadException(__(No file upload or serv…...
二、k8s项目的生命周期
项目的生命周期 创建-----------》发布-----------》更新--------》回滚----------》删除 kubectl create deployment nginx1 --imagenginx:1.22 --replicas3 基于deployment控制器创建pod 控制器的名称是nginx1 pod使用的镜像:nginx:1.22 --replicas3 pod的数量有多少 3个…...
MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 基础篇 part 10
第10章_创建和管理表 DDL:数据定义语言。CREATE \ALTER\ DROP \RENAME TRUNCATE DML:数据操作语言。INSERT \DELETE \UPDATE \SELECT(重中之重) DCL:数据控制语言。COMMIT \…...
python自动化测试之Pytest框架之YAML详解以及Parametrize数据驱动!
一、YAML详解 YAML是一种数据类型,它能够和JSON数据相互转化,它本身也是有很多数据类型可以满足我们接口 的参数类型,扩展名可以是.yml或.yaml 作用: 1.全局配置文件 基础路径,数据库信息,账号信息&…...
deepseek的CoT优势、两阶段训练的有效性学习笔记
文章目录 1 DeepSeek的CoT思维链的优势1.2 open-r1的CoT训练数据1.3 ReAct任务与CoT任务适用场景 2 AI推理方向:deepseek与deepmind的两条路线的差异2.1 PRM与ORM的两大学派分支的差异2.2 DeepSeek-R1的两阶段训练概述 1 DeepSeek的CoT思维链的优势 DeepSeek跟之前…...
计算机网络-MPLS转发原理
在上一篇关于 MPLS 基础的文章中,我们了解了 MPLS 的基本概念、术语以及它在网络中的重要性。今天,我们将深入探讨 MPLS 转发的原理与流程,帮助大家更好地理解 MPLS 是如何在实际网络中工作的。 一、MPLS 转发概述 MPLS 转发的本质是将数据…...
本地部署DeepSeek R1并搭建Web UI实现可视化交互的笔记
经过多天的挣扎和卸载了一些软件,终于下定决心在本地部署DeepSeek R1模型。部署和搭建过程非常简单和方便。 一、下载Ollama 进入Ollama官方网站(https://ollama.com),进入下载下载Ollama页面(https://ollama.com/download) 根据电脑的操作…...
港中文腾讯提出可穿戴3D资产生成方法BAG,可自动生成服装和配饰等3D资产如,并适应特定的人体模型。
今天给大家介绍一种名为BAG(Body-Aligned 3D Wearable Asset Generation)的新方法,可以自动生成可穿戴的3D资产,如服装和配饰,以适应特定的人体模型。BAG方法通过构建一个多视图图像扩散模型,生成与人体对齐…...
JUC并发—1.Java集合包底层源码剖析
大纲 1.为什么要对JDK源码剖析 2.ArrayList源码一:基本原理以及优缺点 3.ArrayList源码二:核心方法的原理 4.ArrayList源码三:数组扩容以及元素拷贝 5.LinkedList源码一:优缺点和使用场景 6.LinkedList源码二:双…...
使用Java爬虫获取京东商品评论API接口(JD.item_review)数据
一、引言 在电商领域,商品评论是用户决策的重要参考依据,也是商家优化产品和服务的重要数据来源。京东作为国内领先的电商平台,提供了丰富的API接口供开发者使用,其中JD.item_review接口可以获取商品的评论数据。通过这些数据&am…...
问卷数据分析|SPSS实操之单因素方差分析
适用条件: 检验分类变量和定量变量之间的差异 分类变量数量要大于等于三 具体操作: 1.选择分析--比较平均值--单因素ANOVA检验 2. 下方填分类变量,上方为各个量表数据Z1-Y2 3. 点击选项,选择描述和方差齐性检验 4.此处为结果数…...
【自然语言处理】TextRank 算法提取关键词、短语、句(Python源码实现)
文章目录 一、TextRank 算法提取关键词 [工具包]二、TextRank 算法提取关键短语[工具包]三、TextRank 算法提取关键句[工具包]四、TextRank 算法提取关键句(Python源码实现) 一、TextRank 算法提取关键词 [工具包] 见链接 【自然语言处理】TextRank 算法…...
Git的常用命令及常见问题处理方法
目录 一、介绍二、常用 Git 命令1. 配置用户信息2. 初始化仓库3. 克隆远程仓库4. 查看状态5. 添加文件到暂存区6. 提交更改7. 查看提交历史8. 查看文件差异9. 查看分支10. 切换分支11. 合并分支12. 处理冲突13. 远程操作14. 标签管理15. 撤销操作 三、常见问题处理方法1. 无法推…...
第6章 6.1 ASP.NET Core MVC 项目
6.1.1 ASP.NET Core MVC 项目的搭建 进入VS环境,创建新的项目,选择【ASP.Net Core Web 应用(模型-视图-控制器)】如下图所示 编写项目名称 点击创建,进入项目后结构如下所示 wwwroot 文件夹为图片、JS、CSS等静态文件…...
ios通过xib创建控件
之前写过ios动态创建控件及添加事件,纯手工代码写控件,虽然比较灵活,但是就是代码量比较多。这次我们通过xib来创建app下载列表项 AppView.xib。一个imageview,一个label,一个button构成 1.创建AppView.xib 2.再创建xib对应的mode࿰…...
缓存组件<keep-alive>
缓存组件<keep-alive> 1.组件作用 组件, 默认会缓存内部的所有组件实例,当组件需要缓存时首先考虑使用此组件。 2.使用场景 场景1:tab切换时,对应的组件保持原状态,使用keep-alive组件 使用:KeepAlive | Vu…...