Redis数据类型及底层实现

news2024/12/26 23:04:43

文章目录

      • 1.3.1 5种基本数据类型
        • 1.3.1.1 总结篇
        • 1.3.1.2 底层源码引入篇
          • 1.3.1.2.1 redis是字典数据库KV键值对到底是什么
          • 1.3.1.2.2 数据类型视角
          • 1.3.1.2.3 数据模型解析(重点)
          • 1.3.1.2.4 redisObjec
          • 1.3.1.2.5 SDS
        • 1.3.1.3 String
          • 1.3.1.3.1 底层分析
            • 1.3.1.3.1.1 数据结构
            • 1.3.1.3.1.2 源码分析
            • 1.3.1.3.1.3 INT 编码格式(set k1 123)
            • 1.3.1.3.1.4 EMBSTR编码格式(set k1 abc)
            • 1.3.1.3.1.5 raw 编码格式(set k1 大于44长度的一个字符串)
        • 1.3.1.4 Hash
          • 1.3.1.4.1 底层分析
            • 1.3.1.4.1.1 验证编码
            • 1.3.1.4.1.2 源码分析
            • 1.3.1.4.1.3 Ziplist
            • 1.3.1.4.1.4 hashtable
        • 1.3.1.5 List
          • 1.3.1.5.1 底层分析
            • 1.3.1.5.1.1 验证编码
            • 1.3.1.5.1.2 数据结构
            • 1.3.1.5.1.3 源码分析
        • 1.3.1.6 Set
          • 1.3.1.6.1 底层分析
            • 1.3.1.6.1.1 编码验证
            • 1.3.1.6.1.2 数据结构
        • 1.3.1.7 Zset
          • 1.3.1.7.1 底层分析
            • 1.3.1.7.1.1 编码验证
            • 1.3.1.7.1.2 数据结构(skiplist)
            • 1.3.1.7.1.3 源码分析
      • 1.3.2 3种新类型bitmap/hyperloglgo/GEO
        • 1.3.2.1 出现背景分析及统计类型
        • 1.3.2.2 Bitmap
          • 1.3.2.2.1 数据结构
          • 1.3.2.2.2 编码验证
        • 1.3.2.3 Hyperloglog
          • 1.3.2.3.1 计数算法
          • 1.3.2.3.2 HyPerLogLog如何做的?如何演化出来的?
          • 1.3.2.3.3 为什么redis集群的最大槽数是16384个?
          • 1.3.2.3.4 天猫网站首页亿级UV的Redis统计方案
        • 1.3.2.4 GEO
          • 1.3.2.4.1 案例:美团地图位置附近的酒店推送

官网命令大全: http://doc.redisfans.com/,命令不区分大小写,而key是区分大小写的,help @类型名词

1.3.1 5种基本数据类型

程序员写代码时脑子底层思维

总结:

1.3.1.1 总结篇

不同数据类型对应的底层数据结构:
1. 字符串
int:8个字节的长整型。
embstr:小于等于44个字节的字符串。
raw:大于44个字节的字符串。
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。
2. 哈希(ziplist(压缩列表)+hashtable(哈希表))
ziplist(压缩列表):元素个数<512,值长度<64字节,否则,hashtable(哈希表)
ziplist内存连续紧凑,时间换空间,适合内存中数据少的情况
hashtable:读写时间复杂度为O(1)
3.列表(ziplist(压缩列表)+linkedlist(链表))
Ziplist:元素个数<512,值长度<64字节,否则,inkedlist(链表)
4. 集合(intset(整数集合)+hashtable(哈希表))
Intset:元素个数小于512,否则,hashtable
Redis会选用intset来作为集合的内部实现,从而减少内存的使用。
5. 有序集合(ziplist(压缩列表)+skiplist(跳跃表))
ziplist:元素个数<128,元素值长度<64字节,否则,skiplist

1.3.1.2 底层源码引入篇

redis源码在哪里:redis-6.0.8\redis-6.0.8\src

1.3.1.2.1 redis是字典数据库KV键值对到底是什么

redis是key-value存储系统,其中key类型一般为字符串(SDS),value类型则为redis对象(redisObject)

字典、KV是什么:每个键值对都会有一个dictEntry。类比java Map中的Entry

1.3.1.2.2 数据类型视角


上帝视角:
https://redissrc.readthedocs.io/en/latest/datastruct/dict.html
https://redissrc.readthedocs.io/en/latest/index.html

1.3.1.2.3 数据模型解析(重点)

redisObject +Redis数据类型+Redis 所有编码方式(底层实现)三者之间的关系
简单地说,redisObjec就是string、hash、list、set、zset的父类,可以在函数间传递时隐藏具体的类型信息,所以作者抽象了redisObjec结构来到达同样的目的。

1.3.1.2.4 redisObjec

Redis定义了redisObjec结构体来表示string、hash、list、set、zset等数据类型。
Redis 中每个对象都是一个redisObject结构

redisObject结构作用?
其实无论是设计redisObject,还是对存储字符设计这么多的SDS,都是为了根据存储的不同内容(type和encoding字段)选择不同的存储方式,这样可以实现尽量地节省内存空间和提升查询速度的目的。

  1. 4位的type表示具体的数据类型
  2. 4位的encoding表示该类型的物理编码方式见下表,同一种数据类型可能有不同的编码方式。(比如String就提供了3种:int embstr raw)
  3. lru字段表示当内存超限时采用LRU算法清除内存中的对象。
  4. refcount表示对象的引用计数。
  5. ptr指针指向真正的底层数据结构的指针。

编码类型:

Set age 17后redisObjec:

1.3.1.2.5 SDS


Redis中字符串的实现,SDS有多种结构(sds.h)用于存储不同的长度的字符串:
sdshdr5(2^5=32byte)、sdshdr8(2 ^ 8=256byte)、sdshdr16(2 ^ 16=65536byte=64KB)
sdshdr32(2 ^ 32byte=4GB)、sdshdr64(2的64次方byte=17179869184G)。

**len **表示SDS的长度,获取字符串长度O(1),不像C那样需要遍历一遍字符串。
**alloc **用于计算字符串已经分配的未使用的空间,作用:预分配空间的算法,而不用去考虑内存分配的问题。
buf 表示字符串数组,真存数据的。

Redis为什么重新设计一个 SDS 数据结构?
C语言没有Java里面的String类型,redis自己构建了一种名为简单动态字符串 SDS(simple dynamic string)的抽象类型,并将 SDS 作为 Redis 的默认字符串


1.3.1.3 String


1.3.1.3.1 底层分析

1.3.1.3.1.1 数据结构

详见SDS,总结如下:

1.3.1.3.1.2 源码分析

1.3.1.3.1.3 INT 编码格式(set k1 123)

当字符串键值的内容可以用一个64位有符号整形来表示时,Redis会将键值转化为long型来进行存储,此时即对应 OBJ_ENCODING_INT 编码类型。内部的内存结构表示如下:

Redis启动时会预先建立10000个分别存储09999的redisObject变量作为共享对象,这就意味着如果set字符串的键值在010000之间的话,则可以直接指向共享对象而不需要再建立新对象,此时键值不占空间!
set k1 123、set k2 123使用同一块空间

redis源代码:object.c,通过源码说明确实有10000的预分配


1.3.1.3.1.4 EMBSTR编码格式(set k1 abc)

redis源代码:object.c

对于长度小于 44的字符串,Redis 对键值采用OBJ_ENCODING_EMBSTR 方式,EMBSTR 顾名思义即:embedded string,表示嵌入式的String。从内存结构上来讲 即字符串 sds结构体与其对应的 redisObject 对象分配在同一块连续的内存空间,字符串sds嵌入在redisObject对象之中一样。


1.3.1.3.1.5 raw 编码格式(set k1 大于44长度的一个字符串)


当字符串的键值为长度大于44的超长字符串时,Redis 则会将键值的内部编码方式改为OBJ_ENCODING_RAW格式,这与OBJ_ENCODING_EMBSTR编码方式的不同之处在于,此时动态字符串sds的内存与其依赖的redisObject的内存不再连续

1.3.1.4 Hash


1.3.1.4.1 底层分析

1.3.1.4.1.1 验证编码

hash的两种编码格式:ziplist、hashtable
hash-max-ziplist-entries:使用压缩列表保存时哈希集合中的最大元素个数。
hash-max-ziplist-value:使用压缩列表保存时哈希集合中单个元素的最大长度。

采用哪种编码?
Hash类型键的字段个数小于hash-max-ziplist-entries,并且每个字段名和字段值的长度小于hash-max-ziplist-value时,Redis才会使用OBJ_ENCODING_ZIPLIST来存储该键,前述条件任意一个不满足则会转换为OBJ_ENCODING_HT的编码方式

验证:分别先将这两个值设置为3和8

验证上述选择哪种编码的几种情况:


1.3.1.4.1.2 源码分析

编码变化流程:

1.3.1.4.1.3 Ziplist

ziplist.c权威注释:

Ziplist 压缩列表是一种紧凑编码格式,时间换空间的思想,用于字段个数少,且字段值也较小的场景。压缩列表内存利用率极高的原因与其连续内存的特性是分不开的。
想想我们的学过的一种GC垃圾回收机制:标记–压缩算法,当一个hash对象只包含少量键值对且每个键值对的键和值要么就是小整数要么就是长度比较短的字符串,那么它用ziplist作为底层实现
1.3.1.4.1.3.1 压缩列表节点的构成
组成分为三部分:header+entry集合+end,其中header由zlbytes+zltail+zllen组成
zlbytes 4字节,记录整个压缩列表占用的内存字节数。
zltail 4字节,记录压缩列表表尾节点的位置。
zllen 2字节,记录压缩列表节点个数。
zlentry 列表节点,长度不定,由内容决定。
zlend 1字节,0xFF 标记压缩的结束。该字节为255(1111 1111)

压缩列表是 Redis 为节约空间而实现的一系列特殊编码的连续内存块组成的顺序型数据结构,本质上是字节数组

源代码:ziplist.c
ziplist是一个经过特殊编码的双向链表,它不存储指向上一个链表节点和指向下一个链表节点的指针,而是存储上一个节点长度和当前节点长度,通过牺牲部分读写性能,来换取高效的内存空间利用率,节约内存,是一种时间换空间的思想。只用在字段个数少,字段值小的场景里面

zlentry实体结构解析(链表中元素结构)



压缩列表的遍历:(偏移)
通过指向表尾节点的位置指针p1, 减去节点的previous_entry_length,得到前一个节点起始地址的指针。如此循环,从表尾遍历到表头节点。

ziplist存取情况:


1.3.1.4.1.3.2 明明有链表了,为什么出来一个压缩链表?

1.3.1.4.1.4 hashtable

在 Redis 中,hashtable 被称为字典(dictionary),它是一个数组+链表的结构
t_hash.c:

OBJ_ENCODING_HT 编码分析:(每个键值对都会有一个dictEntry)
OBJ_ENCODING_HT 这种编码方式内部才是真正的哈希表结构,或称为字典结构,其可以实现O(1)复杂度的读写操作,因此效率很高。在 Redis内部,从 OBJ_ENCODING_HT类型到底层真正的散列表数据结构是一层层嵌套下去的,组织关系见面图:

源代码:dict.h


1.3.1.5 List


1.3.1.5.1 底层分析

1.3.1.5.1.1 验证编码



1.3.1.5.1.2 数据结构

List的一种编码格式:list用quicklist来存储,quicklist存储了一个双向链表,每个节点都是一个ziplist

(低版本redis:ziplist+linkedList;高版本redis:quicklist+ziplist)

1.3.1.5.1.3 源码分析

quicklist.h
head和tail指向双向列表的表头和表尾

quicklistNode中的*zl指向一个ziplist,一个ziplist可以存放多个元素


1.3.1.6 Set


1.3.1.6.1 底层分析

1.3.1.6.1.1 编码验证


如果元素都是整数类型,就用intset存储,否则用hashtable(数组+链表的存来储结构)。key就是元素的值,value为null。

将配置设置为3,存储元素超过3个编码改变

验证是否改变

1.3.1.6.1.2 数据结构

t_set.c

1.3.1.7 Zset


1.3.1.7.1 底层分析

1.3.1.7.1.1 编码验证

,超过配置阈值,ziplist转化为skiplist
server.zset_max_ziplist_entries:元素个数
server.zset_max_ziplist_value:元素长度

将阈值调小:

1.3.1.7.1.2 数据结构(skiplist)

跳跃表=链表+多级索引,可以实现二分查找的有序链表,空间换时间的结构
说说链表和数组的优缺点?为什么引出跳表


(解决方法:升维,也叫空间换时间)

跳表的时间复杂度:O(logN)
二分查找,时间复杂度是O(logN)
跳表的空间复杂度:O(N)
首先原始链表长度为n
若索引是每2个结点有一个索引结点,每层索引的结点数:n/2, n/4, n/8 … , 8, 4, 2 以此类推;
若每3个结点有一个索引结点,每层索引的结点数:n/3, n/9, n/27 … , 9, 3, 1 以此类推;
所以空间复杂度是O(n);

优缺点
只有在数据量较大的情况下才能体现出来优势。而且应该是读多写少的情况下才能使用,所以它的适用范围应该还是比较有限的

维护成本相对要高 - 新增或者删除时需要把所有索引都更新一遍;
最后在新增和删除的过程中的更新,时间复杂度也是O(log n)

1.3.1.7.1.3 源码分析

t_zset.c:

1.3.2 3种新类型bitmap/hyperloglgo/GEO

1.3.2.1 出现背景分析及统计类型

出现背景:
实现问题:

  1. 手机App中的每天的⽤⼾登录信息:1天对应1系列⽤⼾ID或移动设备ID;
  2. 电商⽹站上商品的⽤⼾评论列表:1个商品对应了1系列的评论;
  3. ⽤⼾在⼿机App上的签到打卡信息:1天对应1系列⽤⼾的签到记录;
  4. 应⽤⽹站上的⽹⻚访问信息:1个⽹⻚对应1系列的访问点击。
  5. 在移动应用中,需要统计每天的新增用户数和第2天的留存用户数;
  6. 在电商网站的商品评论中,需要统计评论列表中的最新评论;
  7. 在签到打卡中,需要统计一个月内连续打卡的用户数;
  8. 在网页访问记录中,需要统计独立访客(UniqueVisitor,UV)量。

痛点:类似今日头条、抖音、淘宝这样的额用户访问级别都是亿级的,请问如何处理?
统计类型:

排序统计案例:
以抖音vcr最新的留言评价为案例,所有评论需要两个功能,按照时间排序+分页显示
能够排序+分页显示的redis数据结构是什么合适?
分析:在⾯对需要展示最新列表、排行榜等场景时,如果数据更新频繁或者需要分页显示,建议使⽤ZSet(使用Zset分析此处用户对应的评论条数不会太大)

若是使用list,存在分页数据改变问题(个人感觉能接受,不是什么么问题)


1.3.2.2 Bitmap



1.3.2.2.1 数据结构

由0和1状态表现的二进制位的bit数组,底层String实现

位图本质是数组,它是基于String数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们可以称之为一个索引或者位格)。Bitmap支持的最大位数是232位,它可以极大的节约存储空间,使用512M内存就可以存储多大42.9亿的字节信息(232 = 4294967296)

案例:京东签到领取京豆(连续签到问题
在签到统计时,每个用户一天的签到用1个bit位就能表示,
一个月(假设是31天)的签到情况用31个bit位就可以,一年的签到也只需要用365个bit位,根本不用太复杂的集合类型

1.3.2.2.2 编码验证

实质是二进制的ascii编码对应,redis里用type命令看看bitmap实质是什么类型???

两个setbit命令对k1进行设置后,对应的二进制串就是0100 0001
二进制串就是0100 0001对应的10进制就是65,所以见下图:

1.3.2.3 Hyperloglog

用途:


1.3.2.3.1 计数算法

去重复统计功能的基数估计算法-就是HyperLogLog

案例:

1.3.2.3.2 HyPerLogLog如何做的?如何演化出来的?

去重复统计你先会想到哪些方式?HashSet、bitmap,优势在于精确。
HashSet存储原始数据,内存消耗大
Bitmap不存储原始数据,消耗比HashSet,随着数据集越大内存消耗也就越大
为解决内存消耗问题,采用概率算法


1.3.2.3.3 为什么redis集群的最大槽数是16384个?

https://github.com/redis/redis/issues/2576

分析:


1.3.2.3.4 天猫网站首页亿级UV的Redis统计方案


分析:
用redis的hash结构存储,按照ipv4的结构来说明,每个ipv4的地址最多是15个字节,某一天的1.5亿15个字节=2G,一个月60G,redis死定了
Hyperloglog:


为什么是12Kb?
每个桶取6位,16384
6÷8 = 12kb,每个桶有6位,最大全部都是1,值就是63

1.3.2.4 GEO

原理:
地理位置信息,地球上的地理位置是使用二维的经纬度表示,核心思想就是将球体转换为平面,区块转换为一点

难点:GeoHash核心原理解析

1.3.2.4.1 案例:美团地图位置附近的酒店推送


选型:es中地理位置信息 或 redis中geo。此处讲述geo
Redis中应该有一份静态数据(如xxx酒店位置),当我们查找会将我们实时位置上传,将附件满足的位置返回给我们(如:xxx酒店)

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

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

相关文章

Ubuntu Server 22.04 安装步骤纪录

Ubuntu Server 22.04 安装流程 取得安装程序 安装程序可以通过下方链接直接从官网下载就可以了&#xff0c;官网提供的是iso映像文件&#xff0c;安装前要先将iso映像文件刻录成光盘&#xff0c;或制作成USB开机随身碟。 前往 Ubuntu 官网 开始安装 STEP 1 选择要安装的操作…

Python初学者学习记录——python基础综合案例:数据可视化——地图可视化

一、基础地图使用 1、基础地图演示 2、基础地图演示——视觉映射器 from pyecharts.charts import Map from pyecharts.options import VisualMapOpts# 准备地图对象 map Map() # 准备数据 data [("北京市", 99),("上海市", 199),("湖南省", 2…

【GitHub项目推荐--游戏模拟器(switch)】【转载】

01 任天堂模拟器 yuzu 是 GitHub 上斩获 Star 最多的开源 Nintendo Switch 模拟器 &#xff0c;使用 C 编写&#xff0c;考虑到了可移植性&#xff0c;该模拟器包括 Windows 和 Linux 端。 如果你的 PC 满足必要的硬件要求&#xff0c;该模拟器就能够运行大多数商业游戏&…

DC电源模块的发展与创新

BOSHIDA DC电源模块的发展与创新 DC电源模块在过去几十年中经历了许多发展与创新。以下是其中一些重要的方面&#xff1a; 1. 提高功率密度&#xff1a;随着科技的进步&#xff0c;DC电源模块的功率密度不断提高。通过使用更高效的能量转换技术和材料&#xff0c;设计工程师…

盲盒小程序系统:发展趋势和发展魅力

随着“盲盒经济”的蓬勃发展&#xff0c;越来越多的人加入到了盲盒的行列&#xff0c;各类企业商家也纷纷投身到了盲盒的火热中。 盲盒火爆的最大吸引力还是在于其独特的惊喜感和刺激感。盲盒具有不确定性&#xff0c;这种不确定性能够让大众拆开盲盒后感到惊喜。盲盒还具有社…

ServletResponse接口

ServletResponse接口 ServletContext接口向servlet提供关于其运行环境的信息。上下文也称为Servlet上下文或Web上下文,由Web容器创建,用作ServletContext接口的对象。此对象表示Web应用程序在其执行的上下文。Web容器为所部署的每个Web应用程序创建一个ServletContext对象。…

【极数系列】Flink搭建入门项目Demo 秒懂Flink开发运行原理(05)

文章目录 引言1.创建mavenx项目2.包结构3.引入pom依赖4.增加log4j2.properties配置5.创建主启动类6.构建打jar包7.flinkUI页面部署 引言 gitee地址&#xff1a;https://gitee.com/shawsongyue/aurora.git 源码直接下载可运行&#xff0c;模块&#xff1a;aurora_flink Flink 版…

数据结构与算法:复杂度

友友们大家好啊&#xff0c;今天开始正式学习数据结构与算法有关内容&#xff0c;后续不断更新数据结构有关知识内容&#xff0c;希望多多支持&#xff01; 数据结构&#xff1a; 数据结构是用于存储和组织数据的方式&#xff0c;以便可以有效地访问和修改数据。不同的数据结构…

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-友情链接管理实现

锋哥原创的SpringbootLayui python222网站实战&#xff1a; python222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火…

Modern C++ std::tuple的size

不知道大家读过《Modern C std::unique_ptr的实现原理》没有&#xff1f; 里面提到了std::tuple<void*, default_delete()>的大小是4&#xff0c;而不是41或者44&#xff0c;是不是很奇怪&#xff0c;本文不会揭晓答案&#xff0c;只是会扩展测试各种情况。 #include<…

打开 IOS开发者模式

前言 需要 1、辅助设备&#xff1a;苹果电脑&#xff1b; 2、辅助应用&#xff1a;Xcode&#xff1b; 3、准备工作&#xff1a;苹果手机 使用数据线连接 苹果电脑&#xff1b; 当前系统版本 IOS 17.3 通过Xcode激活 两指同时点击 Xcode 显示选择&#xff0c;Open Develop…

私人漫画图书馆:分类管理,一目了然 | 开源日报 No.157

tachiyomiorg/tachiyomi Stars: 26.9k License: Apache-2.0 tachiyomi 是一个免费开源的安卓漫画阅读器。 该项目的主要功能、关键特性、核心优势包括&#xff1a; 从多种来源在线阅读本地阅读已下载内容可配置的阅读器&#xff0c;具有多个查看器、翻页方向和其他设置支持追…

Bug: git stash恢复误drop的提交

Bug: git stash恢复误drop的提交 前几天在写ut时突然需要通过本地代码临时出一个包&#xff0c;但是本地ut又不想直接作为一个commit提交&#xff0c;所以为了省事就将ut的代码暂时stash起来。出完包后想apply stash&#xff0c;但是手误操作点成了drop stash&#xff0c;丢失了…

容器化部署 Jenkins,并配置SSH远程操作服务器

目录 一、Jenkins是什么 二、常见的部署Jenkins的方法 三、为什么选择容器化部署 四、容器化部署Jenkins步骤 1、安装 Docker 2、获取 Jenkins 镜像 3、创建并运行容器 4、访问 Jenkins 4.1 查看初始密码问题 5、配置 Jenkins 5.1 安装插件 5.2 创建管理员用户 5.3…

Git安装详细步骤

目录 1、双击安装包&#xff0c;点击NEXT​编辑 2、更改安装路径&#xff0c;点击NEXT 3、选择安装组件 4、选择开始菜单页 5、选择Git文件默认的编辑器 6、调整PATH环境 7、选择HTTPS后端传输 8、配置行尾符号转换 9、配置终端模拟器与Git Bash一起使用 10、配置额外…

web前端---------盒子模型

1.内容 盒子的内容可以包含文字、图片等多种类型。 浏览器在加载网页时&#xff0c;会将元素按照内容区分为替换元素与非替换元素。 &#xff08;1&#xff09;替换元素指的是HTML中的一些形如<img>、<input>等非文本元素。 这些元素本身不包含任何内容&#x…

【VB测绘程序设计】案例13——几种常用的角度转换子程序Function功能的使用(附源代码)

【VB测绘程序设计】案例13——几种常用的角度转换子程序Function的使用(附源代码) 文章目录 前言一、界面展示二、程序说明三、程序代码1.角度转换子程序jdzh()四、数据演示总结前言 使用VB编写测绘程序,最基础的对于角度在导线测量计算中频繁需要角度的计算,从度分秒转…

Redis核心技术与实战【学习笔记】 - 3.Redis服务高可靠

1.数据同步&#xff1a;主从库如何实现数据一致&#xff1f; 前面我们学习了 AOF 和 RDB&#xff0c;如果 Redis 发生了宕机&#xff0c;它们可以分别通过回放日志和重新读入 RDB 文件的方式恢复数据&#xff0c;从而保证尽量较少丢失数据&#xff0c;提升可靠性。 不过&…

qemu单步调试arm64 linux kernel

一、背景和目的 qemu搭建arm64 linux kernel环境-CSDN博客 之前介绍了qemu启动kernel的配置步骤和方法&#xff0c;现在开始我们的调试&#xff0c;这篇文章主要讲解如何单步调试内核&#xff0c;所有的实验还是基于ARM64&#xff1b; 二、环境准备 需要准备hostx86 target…

vue2中的watch(侦听器)讲解,以及解决深度监听新值和旧值相同的两种方案(手写深拷贝和JSON.parse())。

目录 一&#xff1a;什么是watch? 二&#xff1a;watch的基础使用 1.最基本的使用 2.简写形式 三&#xff1a;watch中的immediate和deep属性 1.immediate属性 2.deep属性 3.解决深度监听新旧值相同的问题 1&#xff09;使用序列化和反序列化。 2&#xff09;手写深…