Redis设计与实现之对象处理机制

目录

一、前言

二、对象处理机制

1、redisObject 数据结构,以及 Redis 的数据类型

2、 命令的类型检查和多态

3、对象共享

4、引用计数以及对象的销毁

三、对象的处理

1、Redis是如何处理字符串对象的?

2、Redis是如何处理列表对象的?

3、Redis是如何处理哈希对象的?

4、Redis是如何处理集合对象的?

5、Redis是如何处理有序集合对象的?

6、Redis是如何处理bitmap对象的?

7、Redis是如何处理hyperloglog对象的?

8、Redis是如何处理地理位置对象的?

9、Redis是如何处理流对象的?

10、Redis是如何处理模块对象的?

四、小结 


一、前言

既然 Redis 的键值对可以保存不同类型的值,那么很自然就需要对键值的类型进行检查以及多态处理。
为了让基于类型的操作更加方便地执行,Redis 创建了自己的类型系统。

在这一部分,我们将对 Redis 所使用的对象系统进行了解,并分别观察字符串、哈希表、列表、集合和有序集类型的底层实现。

二、对象处理机制

在 Redis 的命令中,用于对键(key)进行处理的命令占了很大一部分,而对于键所保存的值的类型(后简称“键的类型” ),键能执行的命令又各不相同。

比如说,LPUSH 和 LLEN 只能用于列表键,而 SADD 和 SRANDMEMBER 只能用于集合 键,等等。

另外一些命令,比如 DEL 、TTL 和 TYPE ,可以用于任何类型的键,但是,要正确实现这些命令,必须为不同类型的键设置不同的处理方式:比如说,删除一个列表键和删除一个字符串 键的操作过程就不太一样。

以上的描述说明,Redis 必须让每个键都带有类型信息,使得程序可以检查键的类型,并为它 选择合适的处理方式。

另外,在前面介绍各个底层数据结构时有提到,Redis 的每一种数据类型,比如字符串、列表、 有序集,它们都拥有不只一种底层实现(Redis 内部称之为编码,encoding),这说明,每当对 某种数据类型的键进行操作时,程序都必须根据键所采取的编码,进行不同的操作。

比如说,集合类型就可以由字典和整数集合两种不同的数据结构实现,但是,当用户执行 ZADD 命令时,他/她应该不必关心集合使用的是什么编码,只要 Redis 能按照 ZADD 命令的 指示,将新元素添加到集合就可以了。

这说明,操作数据类型的命令除了要对键的类型进行检查之外,还需要根据数据类型的不同编 码进行多态处理。

为了解决以上问题,Redis 构建了自己的类型系统,这个系统的主要功能包括: • redisObject 对象。
• 基于redisObject对象的类型检查。
• 基于redisObject对象的显式多态函数。

• 对redisObject进行分配、共享和销毁的机制。 以下小节将分别介绍类型系统的这几个方面。

Note: 因为 C 并不是面向对象语言,这里将 redisObject 称呼为对象一是为了讲述的方便, 二是希望通过模仿 OOP 的常用术语,让这里的内容更容易被理解,redisObject 实际上是只 是一个结构类型。

1、redisObject 数据结构,以及 Redis 的数据类型

redisObject 是 Redis 类型系统的核心,数据库中的每个键、值,以及 Redis 本身处理的参数,都表示为这种数据类型。 redisObject 的定义位于 redis.h :

/*
* Redis 对象 
*/typedef struct redisObject { // 类型unsigned type:4; // 对齐位unsigned notused:2; // 编码方式unsigned encoding:4;// LRU 时间(相对于 server.lruclock)unsigned lru:22; // 引用计数int refcount; // 指向对象的值void *ptr; 
} robj;

type 、encoding 和 ptr 是最重要的三个属性。
type 记录了对象所保存的值的类型,它的值可能是以下常量的其中一个(定义位于 redis.h):

/*
* 对象类型 
*/#define REDIS_STRING 0 // 字符串 
#define REDIS_LIST 1 // 列表#define REDIS_SET 2 // 集合#define REDIS_ZSET 3  // 有序集
#define REDIS_HASH 4 // 哈希表

encoding 记录了对象所保存的值的编码,它的值可能是以下常量的其中一个(定义位于 redis.h):

/*
* 对象编码 
*/#define REDIS_ENCODING_RAW 0 // 编码为字符串
#define REDIS_ENCODING_INT 1 // 编码为整数
#define REDIS_ENCODING_HT 2 // 编码为哈希表 
#define REDIS_ENCODING_ZIPMAP 3 // 编码为 zipmap 
#define REDIS_ENCODING_LINKEDLIST 4 // 编码为双端链表 
#define REDIS_ENCODING_ZIPLIST 5 // 编码为压缩列表 
#define REDIS_ENCODING_INTSET 6 // 编码为整数集合
#define REDIS_ENCODING_SKIPLIST 7 // 编码为跳跃表

ptr 是一个指针,指向实际保存值的数据结构,这个数据结构由 type 属性和 encoding 属性决 定。

举个例子,如果一个 redisObject 的 type 属性为 REDIS_LIST ,encoding 属性为 REDIS_ENCODING_LINKEDLIST ,那么这个对象就是一个 Redis 列表,它的值保存在一个双 端链表内,而 ptr 指针就指向这个双端链表;

另一方面,如果一个 redisObject 的 type 属性为 REDIS_HASH ,encoding 属性为 REDIS_ENCODING_ZIPMAP ,那么这个对象就是一个 Redis 哈希表,它的值保存在一个 zipmap 里,而 ptr 指针就指向这个 zipmap ;诸如此类。

下图展示了 redisObject 、Redis 所有数据类型、以及 Redis 所有编码方式(底层实现)三者 之间的关系:

这个图展示了 Redis 各种数据类型,以及它们的编码方式。
Note: REDIS_ENCODING_ZIPMAP 没有出现在图中,因为从 Redis 2.6 开始,它不再是任何数据类型的底层结构。

2、 命令的类型检查和多态

有了 redisObject 结构的存在,在执行处理数据类型的命令时,进行类型检查和对编码进行多态操作就简单得多了。 当执行一个处理数据类型的命令时,Redis 执行以下步骤:

  1. 根据给定key,在数据库字典中查找和它像对应的redisObject,如果没找到,就返回 NULL。

  2. 检查redisObject的type属性和执行命令所需的类型是否相符,如果不相符,返回类 型错误。

  3. 根据redisObject的encoding属性所指定的编码,选择合适的操作函数来处理底层的 数据结构。

  4. 返回数据结构的操作结果作为命令的返回值。

作为例子,以下展示了对键 key 执行 LPOP 命令的完整过程:

3、对象共享

有一些对象在 Redis 中非常常见,比如命令的返回值 OK 、ERROR 、WRONGTYPE 等字符外,一些小范围的整数,比如个位、十位、百位的整数都非常常见。

为了利用这种常见情况,Redis 在内部使用了一个 Flyweight 模式 :通过预分配一些常见的值 对象,并在多个数据结构之间共享这些对象,程序避免了重复分配的麻烦,也节约了一些 CPU 时间。

Redis 预分配的值对象有如下这些:

  • 各种命令的返回值,比如执行成功时返回的OK,执行错误时返回的ERROR,类型错误时返回的 WRONGTYPE ,命令入队事务时返回的 QUEUED ,等等。

  • 包 括 0 在 内, 小 于 redis.h/REDIS_SHARED_INTEGERS 的 所 有 整 数(REDIS_SHARED_INTEGERS 的默认值为 10000)

    因为命令的回复值直接返回给客户端,所以它们的值无须进行共享;另一方面,如果某个命令 的输入值是一个小于 REDIS_SHARED_INTEGERS 的整数对象,那么当这个对象要被保存进数据 库时,Redis 就会释放原来的值,并将值的指针指向共享对象。作为例子,下图展示了三个列表,它们都带有指向共享对象数组中某个值对象的指针:

    三个列表的值分别为:

  • • 列表 A :[20130101, 300, 10086] ,

  • • 列表 B :[81, 12345678910, 999] ,

  • • 列表 C :[100, 0, -25, 123] 。

    Note: 共享对象只能被带指针的数据结构使用。 需要提醒的一点是,共享对象只能被字典和双端链表这类能带有指针的数据结构使用。

    像整数集合和压缩列表这些只能保存字符串、整数等字面值的内存数据结构,就不能使用共享 对象。

    4、引用计数以及对象的销毁

    当将 redisObject 用作数据库的键或者值,而不是用来储存参数时,对象的生命期是非常长 的,因为 C 语言本身没有自动释放内存的相关机制,如果只依靠程序员的记忆来对对象进行追 踪和销毁,基本是不太可能的。

    另一方面,正如前面提到的,一个共享对象可能被多个数据结构所引用,这时像是“这个对象被 引用了多少次? ”之类的问题就会出现。

    为了解决以上两个问题,Redis 的对象系统使用了引用计数技术来负责维持和销毁对象,它的 运作机制如下:

    • 每个redisObject结构都带有一个refcount属性,指示这个对象被引用了多少次。

  • • 当新创建一个对象时,它的refcount属性被设置为1。

  • 当对一个对象进行共享时,Redis 将这个对象的 refcount 增一。

  • 当使用完一个对象之后,或者取消对共享对象的引用之后,程序将对象的refcount减 一。

  • 当对象的refcount降至0时,这个redisObject结构,以及它所引用的数据结构的内 存,都会被释放。

三、对象的处理

1、Redis是如何处理字符串对象的?

在Redis中,字符串对象是指存储在键值对中的值,Redis使用简单动态字符串(Simple Dynamic String,SDS)数据结构来表示字符串对象。SDS是一种C语言的字符串抽象,类似于C语言中的字符串,但是它比C字符串更灵活并且可以动态修改大小。

当一个字符串被存储在Redis中时,Redis会根据字符串的长度来自动选择使用普通字符串对象或者SDS对象。如果一个字符串的长度小于等于39字节,那么Redis会使用普通字符串对象来表示。普通字符串对象是一个包含了指向字符数组的指针和字符串长度的结构体。如果一个字符串的长度大于39字节,那么Redis会使用SDS对象来表示。SDS对象是一个结构体,包含了字符串的长度、空余空间、字符数组和其他属性。

SDS字符串对象相较于C字符串具有以下优势:

  1. O(1)复杂度的常数时间获取字符串长度,而C字符串需要遍历整个字符串才能获取长度;
  2. 自动扩展和缩小字符串的空间,避免了缓冲区溢出和内存浪费;
  3. 记录了字符串的使用场景,可以根据场景对字符串进行优化处理;
  4. 支持二进制安全,可以存储任意二进制数据。

Redis的字符串对象在内存中以字节数组的形式存储,这使得Redis可以快速地对字符串进行读写操作。此外,Redis还提供了一系列的命令和操作符来处理字符串对象,如获取字符串长度、追加字符串、截取字符串、替换字符串等。通过这些操作,Redis可以高效地处理和操作字符串数据。

2、Redis是如何处理列表对象的?

Redis处理列表对象是通过使用链表数据结构来实现的。在Redis中,列表对象实际上是一个双向链表,每个节点都包含一个指向前一个节点和后一个节点的指针,以及存储实际数据的值。

当我们执行列表操作(例如插入、删除、更新等)时,Redis会根据需要操作链表来实现。例如,当我们执行LPUSH命令向列表的头部插入一个元素时,Redis会创建一个新的节点,并将其放置在头部的位置。之前的头节点将被指向新节点。

由于Redis使用链表来存储列表对象,所以在操作链表时,插入、删除、更新等操作都是常数时间复杂度(O(1))的。这使得Redis非常适合处理需要频繁插入、删除和更新操作的列表场景。

需要注意的是,虽然Redis的列表对象实际上使用链表实现,但它并不是一个完整的链表数据结构,它只实现了链表的基本操作,如插入、删除、更新等。如果需要更复杂的链表操作,可能需要在客户端或服务器端编写自定义逻辑来实现。

3、Redis是如何处理哈希对象的?

Redis中的哈希对象是指一个键值对集合,其中键是一个字符串,值是由字段和字段值组成的映射。Redis使用哈希对象来表示和存储一些类似于对象的数据结构,例如用户信息、商品信息等。

Redis使用一种称为"ziplist"的压缩列表来存储小型哈希对象。ziplist是一种连续的内存结构,可以高效地存储多个键值对。对于小型哈希对象,Redis将整个哈希对象存储在一个ziplist中。

对于较大的哈希对象,Redis会使用一种称为"hashtable"的哈希表来存储。哈希表是一种散列数据结构,可以更高效地处理较大的键值对集合。Redis使用MurmurHash2算法来计算键的哈希值,并使用开链法处理哈希碰撞。

Redis提供了一系列的命令来操作哈希对象,例如HSET、HGET、HDEL等。通过这些命令,可以向哈希对象添加字段、获取字段的值,以及删除字段等操作。

总结起来,Redis使用ziplist和hashtable两种数据结构来处理哈希对象,具体的选择取决于哈希对象的大小。通过使用压缩列表和哈希表,Redis能够高效地处理不同大小的哈希对象,提供快速的读写操作。

4、Redis是如何处理集合对象的?

在Redis中,集合对象是一种无序的、不重复的数据结构。Redis提供了一系列的命令来处理集合对象。以下是一些常用的集合操作命令:

  1. SADD key member [member ...]:向集合中添加一个或多个成员。
  2. SREM key member [member ...]:从集合中移除一个或多个成员。
  3. SCARD key:获取集合的成员数量。
  4. SMEMBERS key:返回集合中的所有成员。
  5. SISMEMBER key member:判断指定成员是否在集合中。
  6. SINTER key [key ...]:返回多个集合的交集。
  7. SUNION key [key ...]:返回多个集合的并集。
  8. SDIFF key [key ...]:返回多个集合的差集。
  9. SRANDMEMBER key [count]:随机获取集合中的一个或多个成员。
  10. SPOP key [count]:随机移除并返回集合中的一个或多个成员。

Redis的集合对象是基于哈希表实现的,所以集合的添加、删除、查找等操作的时间复杂度都是O(1)。此外,Redis还提供了一些集合操作的命令,如求交集、并集、差集等,这些操作的时间复杂度取决于操作的集合数量。

5、Redis是如何处理有序集合对象的?

在Redis中,有序集合(Sorted Set)是一个集合,其中的每个成员都关联着一个分数,分数用于对成员进行排序。有序集合的成员是唯一的,但分数可以重复。

Redis使用一种叫做跳跃表(Skip List)的数据结构来实现有序集合。跳跃表是一个有序的链表,并且通过一些特殊的指针,使得查找操作可以快速跳到链表的某个位置。

在跳跃表中,每个节点都保存了一个成员以及其对应的分数。通过比较成员的分数,可以进行排序。每个节点还保存了一个向右的指针,指向链表中下一个节点。此外,每个节点还会有一个向下的指针,指向同一层中的下一个节点。这些向下的指针可以在查找时快速跳过一些节点,从而提高查找的效率。

由于跳跃表是有序的,所以在插入、删除或更新有序集合中的成员时,只需要对跳跃表进行相应的操作即可。这些操作的时间复杂度通常是O(log N),其中N是有序集合中的成员数量。

总之,Redis使用跳跃表来实现有序集合,通过成员的分数进行排序,并提供高效的插入、删除和查找操作。

6、Redis是如何处理bitmap对象的?

Redis使用位图对象(bitmap)来表示一系列的二进制数据。每个bit位可以被设置为0或1。Redis提供了一系列的命令来操作位图对象,包括设置、获取、计数、位运算等。

Redis使用字符串来存储位图对象,每个bit位对应字符串中的一个字符。Redis会将多个bit位存储在同一个字符串中,以节省内存空间。Redis使用字节序来存储位图对象,从左到右依次存储每个bit位。每个字节可以存储8个bit位。

Redis提供了以下命令来操作位图对象:

  • SETBIT key offset value:设置指定位的值,offset表示位的偏移量,value为0或1。如果key不存在,会自动创建一个新的位图对象。
  • GETBIT key offset:获取指定位的值,offset表示位的偏移量。
  • BITCOUNT key [start end]:获取指定范围内的位为1的个数,start和end表示范围的起始和结束位的偏移量。
  • BITOP operation destkey key [key ...]:对多个位图对象进行位运算,并将结果保存到destkey。operation可以是AND、OR、XOR和NOT。
  • 其他还有一些位图相关的命令,如BITPOS, BITFIELD等。

通过以上命令,可以方便地对位图对象进行各种操作,如统计位为1的个数、对多个位图对象进行位运算、判断某个位是否为1等。位图对象在实际应用中常用于统计、计数、过滤、去重等场景。

7、Redis是如何处理hyperloglog对象的?

Redis在处理hyperloglog对象时,使用一种名为HyperLogLog算法的基数估计算法。这种算法可以用于估计一个集合中不重复元素的数量。

具体而言,Redis中的hyperloglog对象实际上是一个稀疏的位数组,由底层的二进制字符串表示。这个位数组的长度是固定的,并且通常较短,以节省内存空间。

在向hyperloglog对象添加元素时,Redis会通过一个哈希函数将元素映射到一个位数组的索引位置,并将对应位置的位设置为1。这样,hyperloglog对象就可以通过统计位数组中为1的位的数量来估计集合中的不重复元素数量。

当用户需要获取估计的集合大小时,Redis会对位数组进行一定的处理,计算其中为1的位的数量,并使用HyperLogLog算法进行修正和估计。这个修正过的估计值会返回给用户。

需要注意的是,HyperLogLog算法是一种概率性算法,所以它提供的估计结果不是精确的。但是,它的估计结果通常非常接近实际的集合大小,并且相对于传统的存储方式,它占用的内存空间要大大减少。

8、Redis是如何处理地理位置对象的?

Redis处理地理位置对象的主要方式是使用Geo数据结构。Redis的Geo数据结构使用了有序集合(sorted set),其中地理位置对象被存储为成员(member),而经度和纬度被存储为分数(score)。

通过使用Geo数据结构,Redis提供了一系列的地理位置操作,包括添加地理位置对象、获取地理位置对象的经纬度、计算两个地理位置之间的距离等。

具体地,Redis的Geo数据结构包括以下命令:

  • GEOADD:添加地理位置对象到有序集合中。
  • GEORADIUS和GEORADIUSBYMEMBER:根据给定的经纬度和半径,获取在指定范围内的地理位置对象。
  • GEOPOS:获取地理位置对象的经纬度。
  • GEODIST:计算两个地理位置之间的距离。

通过这些命令,Redis可以高效地处理地理位置对象,并提供丰富的地理位置操作功能。

9、Redis是如何处理流对象的?

Redis是一个键值存储数据库,它将数据存储为键值对。在Redis中,可以将流对象存储为一个字符串类型的值。

当需要处理流对象时,可以使用Redis提供的一些命令和数据结构。以下是几个常用的处理流对象的方式:

  1. 字符串操作:使用Redis提供的字符串操作命令,例如GET和SET命令,可以将流对象存储为字符串,并且可以对字符串进行增删改查的操作。

  2. 列表操作:使用Redis提供的列表数据结构,例如LPUSH和RPUSH命令,可以将流对象存储为列表中的元素,可以通过索引对列表进行读取和修改。

  3. 哈希操作:使用Redis提供的哈希数据结构,例如HSET和HGET命令,可以将流对象存储为哈希表中的字段和值,可以通过字段进行读取和修改。

  4. 集合操作:使用Redis提供的集合数据结构,例如SADD和SMEMBERS命令,可以将流对象存储为集合中的元素,可以对集合进行交集、并集和差集等操作。

除了上述的基本操作,Redis还提供了更高级的功能,如发布/订阅模式、事务、Lua脚本等,可以更灵活地处理流对象的存储和操作。

总的来说,Redis通过将流对象存储为字符串、列表、哈希表或集合等不同的数据结构来处理流对象,并且提供了一系列的命令和数据结构,使得对流对象的操作更加方便和高效。

10、Redis是如何处理模块对象的?

在Redis中,模块对象是通过Module API来处理的。Redis模块允许开发者通过编写C语言代码来创建自定义的模块,为Redis添加新的功能和命令。

模块对象在Redis中被表示为一个结构体,包含一些成员变量和方法。其中,成员变量用于存储模块的状态和数据,而方法用于实现模块的功能和处理请求。

Redis提供了一组函数和宏来注册模块对象并与其进行交互。开发者可以使用RedisModule_CreateCommand函数注册自定义命令,使用RedisModule_Call函数调用命令,使用RedisModule_ReplyWith...系列函数回复客户端请求。

模块对象可以在Redis的运行时加载和卸载。在加载模块时,Redis会调用模块的初始化函数来进行一些必要的初始化工作。在卸载模块时,Redis会调用模块的清理函数来释放资源和回收内存。

通过模块对象,开发者可以实现自定义的数据类型、数据结构和命令,扩展Redis的功能和性能。

四、小结 

  • Redis 使用自己实现的对象机制来实现类型判断、命令多态和基于引用计数的垃圾回收。

  • 一种 Redis 类型的键可以有多种底层实现。

  • Redis 会预分配一些常用的数据对象,并通过共享这些对象来减少内存占用,和避免频繁 地为小对象分配内存。

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

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

相关文章

十九)Stable Diffusion使用教程:ai室内设计案例

今天我们聊聊如何通过SD进行室内设计装修。 方式一:controlnet的seg模型 基础起手式: 选择常用算法,抽卡: 抽到喜欢的图片之后,拖到controlnet里: 选择seg的ade20k预处理器,点击爆炸按钮,得到seg语义分割图,下载下来: 根据语义分割表里的颜色值,到PS里进行修改: 语…

制作一个简单 的maven plugin

流程 首先&#xff0c; 你需要创建一个Maven项目&#xff0c;推荐用idea 创建项目 会自动配置插件 pom.xml文件中添加以下配置&#xff1a; <project> <!-- 项目的基本信息 --> <groupId>com.example</groupId> <artifactId>my-maven-plugi…

深入理解JVM设计的精髓与独特之处

这是Java代码的执行过程 从软件工程的视角去深入拆解&#xff0c;无疑极具吸引力&#xff1a;首个阶段仅依赖于源高级语言的细微之处&#xff0c;而第二阶段则仅仅专注于目标机器语言的特质。 不可否认&#xff0c;在这两个编译阶段之间的衔接&#xff08;具体指明中间处理步…

javacv的视频截图功能

之前做了一个资源库的小项目&#xff0c;因为上传资源文件包含视频等附件&#xff0c;所以就需要时用到这个功能。通过对视频截图&#xff0c;然后作为封面缩略图&#xff0c;达到美观效果。 首先呢&#xff0c;需要准备相关的jar包&#xff0c;之前我用的是低版本的1.4.2&…

极简Excel公式拆分合并单元格并自动填充

例如这个表格&#xff1a; 我们希望拆分合并单元格&#xff0c;并填充到E列。结果如&#xff1a; 步骤 1&#xff09;在E2输入公式如下&#xff1a; LOOKUP(2,1/($B$2:B2<>""),$B$2:B2) 2&#xff09;下拉E2至E9将公式填充即可 注意&#xff1a;公式中的$…

基于ssm游戏美术外包管理信息系统源码和论文

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;线下管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

[Linux] Apache的配置与运用

一、web虚拟主机的构台服务器上运行多个网站&#xff0c;每个网站实际上并不独立占用整个服务器&#xff0c;因此称为"虚拟"虚拟主机的虚拟主机服务可以让您充分利用服务器的硬件资源&#xff0c;大大降低了建立和运营网站的成本 Httpd服务使构建虚拟主机服务器变得容…

基于SSM的志愿者管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

6.23删除二叉搜索树中的节点(LC450-M)

算法&#xff1a; 一共有五种可能的情况&#xff1a; 第一种情况&#xff1a;没找到删除的节点&#xff0c;遍历到空节点直接返回了找到删除的节点 第二种情况&#xff1a;左右孩子都为空&#xff08;叶子节点&#xff09;&#xff0c;直接删除节点&#xff0c; 返回NULL为根…

基于springboot乐器视频学习网站设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

讲座 | 颠覆传统摄像方式乃至计算机视觉的“脉冲视觉”

传统相机拍摄视频时其实是以一定帧率进行采样&#xff0c;视频其实还是一串图片的集合&#xff0c;因此低帧率时会觉得视频卡&#xff0c;拍摄高速运动物体时会有运动模糊等等问题。然而你能想象这一切都可以被“脉冲视觉”这一前沿技术改变吗&#xff1f; 今天下午听了北京大学…

【从零开始学习JVM | 第七篇】深入了解 堆回收

前言&#xff1a; Java堆作为内存管理中最核心的一部分&#xff0c;承担着对象实例的存储和管理任务。堆内存的高效使用对于保障程序的性能和稳定性至关重要。因此&#xff0c;深入理解Java堆回收的原理、机制和优化策略&#xff0c;对于Java开发人员具有重要的意义。 本文旨在…

C++相关闲碎记录(16)

1、正则表达式 &#xff08;1&#xff09;regex的匹配和查找接口 #include <regex> #include <iostream> using namespace std;void out (bool b) {cout << ( b ? "found" : "not found") << endl; }int main() {// find XML/H…

ProroBuf C++笔记

一.什么是protobuf Protocol Buffers是Google的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法&#xff0c;它可⽤于&#xff08;数据&#xff09;通信协议、数据存储等。Protocol Buffers 类⽐于XML&#xff0c;是⼀种灵活&#xff0c;⾼效&#xff0c;⾃动化机制的结…

SpringData自定义操作

一、JPQL和SQL 查询 package com.kuang.repositories;import com.kuang.pojo.Customer; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingR…

javaEE -17(13000字 CSS3 入门级教程)

一&#xff1a;CSS3 简介 CSS3 是 CSS2 的升级版本&#xff0c;它在 CSS2 的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题&#xff0c;CSS3 在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …

Guardrails for Amazon Bedrock 基于具体使用案例与负责任 AI 政策实现定制式安全保障(预览版)

作为负责任的人工智能&#xff08;AI&#xff09;战略的一部分&#xff0c;您现在可以使用 Guardrails for Amazon Bedrock&#xff08;预览版&#xff09;&#xff0c;实施专为您的用例和负责任的人工智能政策而定制的保障措施&#xff0c;以此促进用户与生成式人工智能应用程…

智能优化算法应用:基于哈里斯鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于哈里斯鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于哈里斯鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.哈里斯鹰算法4.实验参数设定5.算法结果6.…

linux性能优化-上下文切换

如何理解上下文切换 Linux 是一个多任务操作系统&#xff0c;它支持远大于 CPU 数量的任务同时运行&#xff0c;这是通过频繁的上下文切换、将CPU轮流分配给不同任务从而实现的。 CPU 上下文切换&#xff0c;就是先把前一个任务的 CPU 上下文&#xff08;CPU 寄存器和程序计数…

JVM学习之JVM概述

JVM的整体结构 Hotspot VM是目前市面上高性能虚拟机代表作之一 它采用解释器与即时编译器并存的架构 在今天&#xff0c;Java程序的运行性能已经达到了可以和C/C程序一较高下的地步 Java代码执行流程 具体图为 JVM架构模型 Java编译器输入的指令流基本上是一种基于 栈的指令…