CMU 15-213 CSAPP. Ch11. Dynamic Memory Allocation

news2024/11/28 20:34:01

CMU 15-213 CSAPP (Ch1~Ch3)
CMU 15-213 CSAPP (Ch5~Ch7)
CMU 15-213 CSAPP (Ch8)
CMU 15-213 CSAPP (Ch9)
CMU 15-213 CSAPP (Ch10)
CMU 15-213 CSAPP (Ch11)
视频链接
课件链接
课程补充
该课程使用 64位 编译器!

Ch11. Dynamic Memory Allocation

11.1 Basic concepts

  • 应用程序通过 Allocator ( 如 malloc ) 在 application 运行后指定 virtual memory size,获取 并 释放 “堆” ( Heap ) 中的 虚拟内存块;
  • Allocator maintaiins the heap as a contiguous collection of blocks;
    • ”已分配使用“
    • ”已释放 待使用“;
  • Allocators 主要分为两类:
    • 显式 ( explicit ),如 C 语言中的 malloc 和 free,分配与释放 完全由 application 自行控制;
    • 隐式 ( implicit ),如 Java、ML、Lisp 等,application 分配,但由 system 的 ”垃圾回收“ ( Garbage collection ) 释放内存;

11.1.1 The malloc Package

  • Allocators in C is provided by standard C library, “malloc package”;
#include <stdlib.h>
void *malloc(size_t size);
void free(void *p);
void *calloc(size_t nmemb, size_t size); 
void *realloc(void *ptr, size_t size);  
void *reallocarray(void *ptr, size_t nmemb, size_t size);

#include <unistd.h>  
int brk(void *addr); 
void *sbrk(intptr_t increment);

/********** annotation **********/
brk()  and  sbrk() change the location of the program break, which defines 
the end of the process's data segment (i.e., the program break is the first 
location after the end of the uninitialized data segment).  Increasing the 
program break has the effect of  allocating  memory  to the process; decreasing 
the break deallocates memory.

brk()  sets the end of the data segment to the value specified by addr, when 
that value is reasonable, the system has enough memory, and the process does 
not exceed its maximum data size (see setrlimit(2)).
  
sbrk() increments the program's data space by increment bytes.  Calling sbrk() 
with an increment of 0 can be used to find the current location of 
the program break.
  • void *malloc ( size_t size )
    • 返回 void 指针,指向 至少 size 个字节的内存块;
    • x86 块大小 8 字节对齐,x86-64 块大小 16 字节对齐;
//CentOS
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>
#include <string.h>
int main()
{	
	void *pbrk0 = sbrk(0);
	void *p1 = malloc(1);
	void *pbrk1 = sbrk(0);
	void *p2 = NULL;
	for(int cnt=0;cnt<1000;cnt++) p2 = malloc(0);
	void *pbrk2 = sbrk(0);
	void *p3 = malloc(pow(10,10));
	printf(	"pbrk0 [%p]\n"
		"p1 [%p]\n"	
		"pbrk1 [%p]\n"
		"p2 [%p]\n"
		"pbrk2 [%p]\n"
		"p3 [%p]\n"
		"errno [%d]\n"
		"strerr [%s]\n",
		pbrk0,p1,pbrk1,p2,pbrk2,p3,errno,strerror(errno));
	return 0;
}
[root@localhost allo]# uname -a
Linux localhost.localdomain 4.18.0-240.el8.x86_64 #1 SMP Fri Sep 25 19:48:47 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost]# gcc a.c 
[root@localhost]# ./a.out 
pbrk0	[0xfda000]
p1		[0xfda2a0]
pbrk1	[0xffb000]
p2		[0xfe1fa0] // 0xfe1fa0 - 0xfda2a0 = 0x7d00 = 32 * 1000
pbrk2	[0xffb000] // 0xffb000 - 0xfda000 = 0x21000, 编译时就决定 “一次性移动一大步”
p3		[(nil)]
errno	[12]
error	[Cannot allocate memory]
  • void free ( void *p )
    • Returns the block pointed at by p to pool of available memory
    • p must come from a previous call to malloc、calloc ( 公开课上发音 “c” “alloc” ) or realloc;

11.1.2 How to implement malloc and free ?

  • Assumption
    • 内存 以 word 为最小单元编址,( on x86 ) word = 4 bytes;
    • malloc、free 入参单位为 word;请添加图片描述
  • Constraints
    • Application 调用 malloc 和 free 的顺序随机;
    • free 的入参必须是 指向已分配内存块的 指针;
    • 请求的 块大小 或 数量 不可控;
    • 请求 必须立即响应 ( 不可以 囤一堆请求一次性响应,或 重排请求的先后顺序 ) ;
    • 只能用 free memory 响应请求,一旦分配 allocators 再也无权访问;
      • allocator can’t compress or smoosh them all together to create larger free blocks;
    • 大小对齐 8-byte (x86) or 16-byte (x86-64);
  • Performance Goal
    Allocators combine a trade-off of both running time ( speed ) and space. So these speed and memory efficiency metrics are defined;
    • Troughput
      Number of completed requests per unit time,eg:5000 malloc calls + 5000 free calls in 10 sec,throughput is 1000 ops/sec;
    • Peak Memory Utilization ( U k U_k Uk )
      U k = m a x ( ∑ i < k P i ) H k U_k=\frac{max( \sum\limits_{i<k}{P_i} )}{H_k} Uk=Hkmax(i<kPi)
      Payloadmalloc ( p ),result in a block with a payload of p bytes;
      Aggregate payload P k P_k Pk,the sum of currently allocated payload after request R 1 , R 2 . . . R k R_1,R_2 ... R_k R1R2...Rk has completed;
      Current heap size H k H_k Hk
  • 实现一个 allocator 需要面对的问题 ( answers in implicit free list )
    • How much memory to free given just a pointer ?
    • How to keep track of the free blocks ?
    • How to deal with extra space when requiring blocks smaller than free blocks it is placed in ?
    • How to choose a specific block among so many free blocks ?
    • How to reinsert freed blocks ?

11.1.3 Fragmentation

  • Internal Fragmentation
    • payload is smaller than block size;
    • like padding for alignment,overhead for maintaining,explicit policy ( don’t want to splinter blocks up into little chunks );
    • depends only on the pattern of previous requests,easy to measure;
  • External Fragmentation
    • aggregate heap memory is enough,but no single free block satisfied request;
    • depends on the pattern of future requests,difficult to measure;
      在这里插入图片描述

11.2 Implicit free lists

  • Knowing How Much to Free
    • standard method
      把 size 藏在 block 开头的的 word 中,这个 word 被称为 header field 或者 header;
  • Keeping Track of Free Blocks
    • 【1】Implicit list
      Traversing all free blocks in heap by traversing all blocks,ignoring allocated blocks;
      There is no list of free blocks,but the headers in blocks can tell;
      与 blocks 的总数线性相关;
    • 【2】Explicit list
      Use some of the words in the block to create singly or doubly linked lists;
      与 free blocks 的总数线性相关,效率略有提升;
    • 【3】Segregated free list
      Different free lists for different size classes;
    • 【4】Blocks sorted by size
      Use a balanced tree (e.g. Red-Black tree) with pointers and the length used as a key

11.2.1 Implicit List

  • Each block needs size and allocation status,standard trick:

    • Blocks has to be aligned,low-order bits are always 0,use it as a allocated / free flag;
    • Must mask out this bit when read size of blocks;
    • 例子

      payload 的起始地址要求 2字对齐,导致 block size 2字对齐,header 在当前 payload 的前一个word;最后,留一个 0 size block 标志 heap 的结尾(合并 free blocks 时消除特殊情况);
  • Finding a Free Block

    • 【First Fit】Search from beginning,choose first free block that fits;It can cause “splinters” at beginning of list;Take linear time in total number of blocks;
    void *search_free_block(int len)
    {
    	void *p = list.begin();
    	alloc = (*p & 1); // 是否被分配
    	tsize = (*p & -2); // free block 总大小 (Byte)
    	psize = tsize - 4; // max_payload = tsize - header_size (Byte)
    	while( p<list.end() && (alloc || psize<len)) //已被分配 或 大小不满足请求
    		p = p + tsize/4; //next block (word addressed)
    	return p;
    }
    
    • 【Next Fit】Search from where previous search finished;Obviously faster than first fit ( avoid re-scanning unhelpful blocks );fragmentation maybe worse;
    • 【Best Fit】Search list and choose the best free block ( closest to size required ) ;less fragmentation but slower than first fit;infinite segregated free list is one way to approach best fit;
  • Allocating in Free Block

    • Split the block if size required is smaller than free block,or just return the whole block ?
void addblock(void *p, int len)
{
	// arithmetic shift, round up to even(远零取整),两字节对齐
  	int newsize = ((len + 1) >> 1) << 1;  	
  	
  	int oldsize = *p & -2;  // mask out status bit
  	*p = newsize | 1;       // set length and allocted status of new block
  	if (newsize < oldsize)	// set length of remaining free block
    	*(p + newsize) = oldsize - newsize; 
}  
void * malloc(int len)
{
	void *p = NULL; 
	p = search_free_block();
	if(p) addblock(p,len + 4); // header size = 4 Bytes
	return p + 1; // (p + 4 bytes) addresse of payload 
}
  • Freeing a Block
    • only clear “allocated” status ? Generating external fragmentation !!
    • Adjacent free blocks need to be coalesced
    • All decent allocator is that contiguous free blocks never exist
void free_block(ptr p)
{
	*p = *p & -2;   		// clear allocated flag
	next = p + (*p)/4;     	// find next block header
	if ((*next & 1) == 0)  	// if not allocated
		*p = *p + *next; 	// add to this block
}
  • How to Coalescing previous block
    • remember the previous block while traverse the list,very inefficient !
    • Bidirectional Coalescing
      • Boundary tags [ Don Kunth 1973 ];
        Replicate header at end of free blocks ( a.k.a. “footer” ),这样 free§ 的时候,p-1 便是 前一个 block 的 “footer”(即 “header”),从而判断是否与前一个 block 进行 Coalescing;缺点是 overhead 变大;

        4 cases:
            
            

Allocated block 都没有 footer;怎样才能在没有 footer 的条件下判断 previous block 是否 allocated
如果 previous block 是 allocated 状态,则它不参与合并,footer也就没有存在的必要 !!
但没有 “footer” 又不能判断 previous block 是否被 allocated,怎么办?
字节对齐导致 header 的低 n 位都是 0 !
malloc 时在其 一个 header 中用一个 低位记录 “allocated” 状态;

11.3 Explicit free lists

Implicit Free List 是由 block 的 length 隐式构建的单向链表,链表节点在虚拟地址上也是连续的;
而 Explicit 则是由 指针 显式构建的双向链表,链表节点间的相对位置随机;

11.3.1 Allocating

只需要更新 4个指针;

11.3.2 Freeing

核心问题:Where to insert the newly freed block ?

  • LIFO (last - in - first - out) Policy
    • free list 的开头插入新释放的 block;
    • 实现简单,时间复杂度 O(1);
    • 研究表明 碎片较 Address-ordered 更多;
  • Address-ordered Policy
    • pre 块地址 < newly freed 块地址 < next 块地址;
    • 需要 search,可以通过 平衡树 等方法加速;
    • 碎片较少;

很多程序员会犯 过早优化 ( premature optimization ) 的错误,刚开始就思考奇奇怪怪的场景和对应的优化措施;在解决 allocator 这样复杂的问题的时候,应该本着“先易后难” 的原则,先有基础方案,再找瓶颈 并 逐个优化;

为方便描述,使用 predecessor 和 successor 分别表示 虚拟地址(VA)前后相邻,而用 prev 和 next 表示 free list 中的前后相连;

LIFO Case 1 前后都不用 coalescing;

LIFO Case 2 与 predecessor 进行 coalescing;

LIFO Case 3 与 successor 进行 coalescing;

LIFO Case 4 与 successor、predecessor 同时 coalescing;

11.3.3 Explicit List Summary

  • v.s. Implicit List
    • Faster,seaching free list only instead of whole heap ( especially when most of the memory is full );
    • More complicated splicing business;
    • Extra space for linked list pointers;

11.4 Segregated free lists

Each size class has its own free list;

  • To allocato a block of size n:

    • Seach appropriate free lists of blocks of requiring size m ( If the block is not found, try next larger class );
    • Place split block on appropriate list ( optional, may be class size exactly equal to the requiring size )
    • If no block is found:
      • Request additional heap memory from OS ( sbrk() );
      • Allocate block of n bytes from this new memory;
      • Place remainder (剩余的块) as a single free block in largest size class;
  • To free a block;

    • Coalesce (like before) and place on appropriate list;
  • Advantages of seglist allocators

    • Higher throughput,快:
      二分查找 合适大小的空闲块链表,log time for power-of-two size classes;
    • Better memory utilization,省:
      对 seglist 的 First-fit search 几乎等效于 对整个 heap 进行了 best-fit search;

sbrk 是 Syscall,花费约几百微妙,overhead 很大,通过 一次 sbrk 申请一个超大块的方式,amortize (均摊) 时间开销;但同时,memory utilization 将变得很低;又一个 space – time trade – off

Seglist 存放在 heap 的起始位置 (见 malloc Lab);
More read:
“Dynamic Storage Allocation: A Survey and Critical Review”

11.5 Implicit Memory Management: Garbage Collection

  • Automatic reclamation of heap-allocated storage;
  • Common in many dynamic languages;
    Python, Ruby, Java, Perl, ML, Lisp, Mathematica;
  • Variants (“conservative” garbage collectors) exist for C and C++
    Allocator can’t determine whether these blocks are indeed garbage;
void foo(){
	int *p = malloc(128); // garbage
	return;
}

11.5.1 Garbage Collection

  • Which memory can be freed?
    • 扫描内存,辨别指针及被其指向的块,没有被指向的块,认为是 Garbage;
  • Assumptions about pointers
    • Memory Manager 需要能分辨出哪些变量是指针;
    • 假设 指针都指向 块的开头(反例如 指向数组中元素的指针);
    • 指针必须是静态不可变的?
  • Classical GC Algorithms
    • Mark-and-sweep collection (McCarthy, 1960)
    • Reference counting (Collins, 1960)
    • Copying collection (Minsky, 1963)
    • Generational Collectors (Lieberman and Hewitt, 1983)
      • Collection based on lifetimes;
      • Most allocations become garbage very soon;
      • So focus reclamation work on zones of memory recently allocated;

More information “Garbage Collection: Algorithms for Automatic Dynamic Memory”, John Wiley & Sons, 1996.

  • Mark-and-sweep collection
    • Each block is a node in graph;
    • Each pointer is a edge in the graph;
    • Locations not in the heap that contain pointers into the heap are calld root nodes (e.g. registers, locations on the stack, global variables);
    • A node is reachable if there is a path from any root to that node;
      Non-reachable nodes are garbage;
    • Implement on top of malloc / free package
      • Allocate using malloc until you “run out of space”;
      • When out of space,use extra mark bit in the head of each block;
      • Sub phase 1,mark,start from all roots and set mark bit on each reachable block( depth-first traversal );
      • Sub phase 2,scan all blocks,and free blocks that are not marked;
    • A Simple Implementation
ptr mark(ptr p) 						// pointer to the payload
{
   if (false == is_ptr(p)) return;     	// do nothing if not pointer
   if (true == markBitSet(p)) return;	// check if already marked
   setMarkBit(p);                 		// set the mark bit
   for (i=0; i < length(p); i++)  		// mark() recursively
   		mark(p[i]); 
   return;
}      
ptr sweep(ptr p, ptr end) 
{
   while (p < end) 						// scan the whole heap
   {
      if(true == markBitSet(p)) clearMarkBit(); 	// 正在被引用的块
      else if (true == allocateBitSet(p)) free(p);	// 没有被引用的块
      p += length(p);								// 将 p 指向 next block
}
  • How to find the beginning of the block
    • In C,pointers can point to the middle of a block;
    • Use a balanced binary tree to keep track of all allocated blocks (key is start-of-block);
    • Balanced-tree pointers can be stored in header (use two additional words);
    • Search the binary tree,a pointer should fall in the beginning and end of some allocated block,and that block is reachable;
    • It’s conservative,because it maybe just an integer,but purportedly points to non-reachable blocks;

11.6 Memory-related perils and pitfalls

Errors involving memory are the worst kind of bugs to try to find out,because they are distant in both space and time;You only find out about those errors when you try to reference that data;

  • Dereferencing bad pointers
  • Reading uninitialized memory
  • Overwriting memory
  • Referencing nonexistent variables
  • Freeing blocks multiple times
  • Referencing freed blocks
  • Failing to free blocks

C pointers,只要根据声明时 运算符的优先级,就不会认错类型;

declarationstype of p
int *ppointer to int
int *p[13]an array[13] of pointer to int
int *(p[13])an array[13] of pointer to int
int (*p)[13]a pointer to an array[13] of int
int (*(*f())[13])()a function returning ptr to an array[13]of pointers to functions returning int
int (*(*x[3])())[5]an array[3] of pointers to functions returning pointers to array[5] of ints

*x[3],[]优先级高,x 是 size 为 3 的数组,其左是*,数组的元素是指针;
*(*x[3])(),数组元素(指针)指向函数,函数的返回值也是指针;
int (*(*x[3])())[5],函数返回的指针,指向 size 为 5 的 int 数组;

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

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

相关文章

【附源码】计算机毕业设计JAVA政府人才机构在线考试系统2021

【附源码】计算机毕业设计JAVA政府人才机构在线考试系统2021 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1…

《web课程设计》基于HTML+CSS+JavaScript典的中医药大学网(11个页面)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

基于Python监测键盘输入并发出声音的坤音键盘

代码和软件在公众号【走神研究所】发送【键盘】关键字获取。这是一款基于python的桌面小工具&#xff0c;能够实时显示你敲击键盘的按键&#xff0c;并且当摁下“J”、“N”、“T”、“M”时会发出坤音。具体视频演示和代码原理在这里打开程序&#xff0c;随意摁下键盘&#xf…

2022/11/27一周总结

项目 redis 安装以及启动 切换到redis根目录运行cmd&#xff0c;先启动服务端redis-server.exe 2.输入redis-cli并回车&#xff08;redis-cli是客户端程序&#xff09;如图正常提示进入&#xff0c;并显示正确端口号&#xff0c;则表示服务已经启动。 基本知识 数据类型 St…

算法提升:图的Dijkstra(迪杰斯特拉)算法

目录 概念 思路 代码 概念 迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的&#xff0c;因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法&#xff0c;解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始&#xf…

【Hack The Box】linux练习-- Ophiuchi

HTB 学习笔记 【Hack The Box】linux练习-- Ophiuchi &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月27日&#x1f334; &#x1…

MySQL的执行计划explain

select_type&#xff1a;表示的查询类型 SIMPLE&#xff1a;表示查询语句不包含子查询和union;PRIMARY&#xff1a;表示此查询是最外层的查询&#xff1b;UNION: 表示此查询是UNION的第二个或后续的查询&#xff1b;DEPENDENT UNION&#xff1a;表示此查询是UNION的第二个或后续…

ARM Developer Keil MDK 5.X Crack

ARM Developer Keil MDK是面向各种STM32微控制器产品的全面软件开发解决方案&#xff0c;提供创建、编译和调试嵌入式应用程序时所需的一切资源。MDK包括真正的Arm编译器和易于使用的Keil uVision IDE/调试器&#xff0c;可与STM32CubeMX和软件包连接。MDK还提供各种专业的中间…

Faster R-CNN详解

Faster R-CNN Faster R-CNN是作者Ross Girshick继Fast R-CNN后的又一力作。使用VGG16作为网络的backbone&#xff0c;推理速度在GPU上达到5fps(包括候选区域的生成)&#xff0c;准确率也有进一步的提升。在2015年的ILSVRC以及COCO竞赛中获得多个项目的第一名。 Faster R-CNN算…

Easyrecovery2022硬盘磁盘U盘免费数据恢复软件

EasyRcovery的软件支持因各种原因损坏或误删的文件&#xff0c;文档&#xff0c;照片&#xff0c;视频&#xff0c;音频&#xff0c;电子邮件等等类型的数据它都可以恢复。同时&#xff0c;这款软件不仅仅支持u盘的数据恢复&#xff0c;移动硬盘&#xff0c;磁盘&#xff0c;sd…

【POJ No. 3067】 公路交叉数 Japan

【POJ No. 3067】 公路交叉数 Japan 北大 OJ 题目地址 【题意】 东海岸有N 个城市&#xff0c;西海岸有M 个城市&#xff08;N ≤1000&#xff0c;M ≤1000&#xff09;&#xff0c;将建成K 条高速公路。每个海岸的城市从北到南编号为1, 2, ……每条高速公路都是直线&#xf…

计算机网络---TCP流量控制和拥塞控制

&#xff08;一&#xff09; TCP 流量控制 TCP提供流量控制服务来消除发送方&#xff08;发送速率太快&#xff09;使接收方缓存区溢出的可能性&#xff0c;因此 流量控制是一个速度匹配服务&#xff08;让发送方慢一点&#xff0c;要让接收方来得及接收&#xff0c;实现匹配发…

Qt编写物联网管理平台(支持win/linux/mac/嵌入式linux/modbus等)

一、前言 这个物联网综合管理平台前后迭代了五年&#xff0c;一点一滴慢慢积累起来&#xff0c;从最开始的只有modbus串口协议解析以及简单的表格显示数据&#xff0c;慢慢的逐渐增加了tcp_rtu支持&#xff0c;用户管理模块&#xff0c;地图监控模块&#xff0c;而后为了拓展性…

消息队列 RabbitMQ入门:Linux(Docker)中安装和卸载RabbitMQ服务

文章目录前言一、Linux中安装RabbitMQ下载Erlang下载RabbitMQ进入Linux进行安装启动RabbitMQ二、RabbitMQ Web管理页面安装RabbitMQ Web管理页面访问管理页面三、使用Docker安装RabbitMQ安装Docker安装启动RabbitMQ访问管理页面四、Linux卸载RabbitMQ相关卸载RabbitMQ卸载Erlan…

第41讲:MySQL内置的QL性能分析工具

文章目录1.SQL性能分析的概念2.分析数据库中SQL的执行频率3.数据库中的慢查询日志3.1.开启慢查询日志功能3.2.模拟慢SQL查询观察日志内容4.Profile查看SQL每个阶段的耗时4.1.开启Profile操作4.2.随便执行一些查询语句4.3.查询执行SQL的耗时4.4.查询某一条SQL每个阶段的耗时4.5.…

【ASM】字节码操作 工具类与常用类 InstructionAdapter 介绍

文章目录 1.概述1.1 为什么会有 InstructionAdapter类?2. InstructionAdapter2.1 class info2.2 fields2.3 构造方法2.4 methods3.示例3.1预期目标4.总结1.概述 在上一节:【ASM】字节码操作 工具类与常用类 AnalyzerAdapter 工作原理 我们学习了AnalyzerAdapter类的工作原理…

【OpenCV 例程 300篇】246. 特征检测之ORB算法

『youcans 的 OpenCV 例程300篇 - 总目录』 【youcans 的 OpenCV 例程 300篇】246. 特征检测之ORB算法 特征检测与匹配是计算机视觉的基本任务&#xff0c;包括检测、描述和匹配三个相互关联的步骤。广泛应用于目标检测、图像检索、视频跟踪和三维重建等诸多领域。 6.9.1 ORB 算…

【Hack The Box】linux练习-- SneakyMailer

HTB 学习笔记 【Hack The Box】linux练习-- SneakyMailer &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月23日&#x1f334; &…

函数调用在嵌入式架构设计中的应用

函数调用很好理解&#xff0c;即使刚学没多久的朋友也知道函数调用是怎么实现的&#xff0c;即调用一个已经封装好的函数&#xff0c;实现某个特定的功能。 把一个或者多个功能通过函数的方式封装起来&#xff0c;对外只提供一个简单的函数接口&#xff0c;然后在其他地方调用即…

SpringCloud - Config分布式配置中心

文章目录一.概述1. 分布式系统面临的配置问题2. 什么是配置中心3. 配置中心怎么用4. 配置中心能做什么二.Config服务端配置与测试1. 搭建1.1 在github上创建一个springcloud_config的新仓库1.2 获得新仓库的地址&#xff1a;1.3 本地硬盘目录上新建git仓库并clone1.4 创建文件1…