当前位置: 首页 > news >正文

【Redis07】Redis基础:Bitmap 与 HyperLogLog 相关操作

Redis基础学习:Bitmap 与 HyperLogLog 相关操作

继续进行 Redis 基础部分的学习,今天我们学习的是两种另外的数据类型。说是数据类型,但其实它们实际上使用的都是 String 类型做为底层基础,只不过是在存储的时候进行了一些特殊的操作。换句话说,这两种类型并不是真正意义上的“数据类型”,换成“数据操作”可能更合适一些。

Bitmap

先来看看 Bitmap ,这是个啥玩意?其实呀,这个就是 位图 ,Bit 就是 比特 的意思嘛。一提到 比特 是不是又得来二进制了?这个真没办法,学计算机的,任何工具都逃不掉的就是 二进制 相关的操作。不过在 Redis 中的操作还是比较简单的,毕竟我们主要的操作还是在程序业务端进行,Redis 只是一个数据库而已。

Bitmap 在 Redis 中可以存储大约 40 多亿条数据,或者说是40多亿个 0 和 1 位。估计不少小伙伴马上就能想到它的应用场景了,我们在最后再说。先来看看它的操作。

Bitmap 操作命令

设置和获取指定位置的位信息,直接使用 SETBIT 和 GETBIT。

127.0.0.1:6379> setbit a 8 1
(integer) 0
127.0.0.1:6379> setbit a 4 1
(integer) 0
127.0.0.1:6379> get a
"\b\x80"
127.0.0.1:6379> getbit a 4
(integer) 1
127.0.0.1:6379> getbit a 5
(integer) 0

注意到上面的例子,我们直接使用 GET 命令也可以获取到内容,前面就说过了,它本身就是使用 String 类型存储的。只不过使用位操作的话,我们要理解 8 位代表 1 个字节的问题。因此,设置一个 8 位的二进制代码才能表示出一个我们能看懂的字符。

127.0.0.1:6379> setbit b 1 1
(integer) 0
127.0.0.1:6379> setbit b 4 1
(integer) 0
127.0.0.1:6379> setbit b 5 1
(integer) 0
127.0.0.1:6379> setbit b 6 1
(integer) 0
127.0.0.1:6379> setbit b 7 1
(integer) 0
127.0.0.1:6379> get b
"O"
127.0.0.1:6379> setbit c 1 1
(integer) 0
127.0.0.1:6379> setbit c 2 1
(integer) 0
127.0.0.1:6379> setbit c 4 1
(integer) 0
127.0.0.1:6379> setbit c 6 1
(integer) 0
127.0.0.1:6379> setbit c 7 1
(integer) 0
127.0.0.1:6379> get c
"k"

看出上面的例子是什么意思了吗?第一个 b ,设置的其实是 01001111 ,转换成十进制是 79 ,对应的 ASC2 码就是大写英文 O 。另一个 c 也是一样的意思,01101011 的十进制是 107 ,表示的英文是 107 。如果要表示 Ok 这两个字母的话,就需要两个 8 位,也就是两个字节 01001111 01101011 。

127.0.0.1:6379> setbit d 1 1
(integer) 0
127.0.0.1:6379> setbit d 4 1
(integer) 0
127.0.0.1:6379> setbit d 5 1
(integer) 0
127.0.0.1:6379> setbit d 6 1
(integer) 0
127.0.0.1:6379> setbit d 7 1
(integer) 0
127.0.0.1:6379> get d
"O"
127.0.0.1:6379> setbit d 9 1
(integer) 0
127.0.0.1:6379> setbit d 10 1
(integer) 0
127.0.0.1:6379> setbit d 12 1
(integer) 0
127.0.0.1:6379> setbit d 14 1
(integer) 0
127.0.0.1:6379> setbit d 15 1
(integer) 0
127.0.0.1:6379> get d
"Ok"

好玩吧?中文也是一样的,只是三个字节的 UTF8 编码,需要三个 8 位的数据才能表示一个中文字,大家可以试试哦。

127.0.0.1:6379> set s 中
OK
127.0.0.1:6379> get s
"\xe4\xb8\xad"
127.0.0.1:6379> getbit s 0
(integer) 1
127.0.0.1:6379> getbit s 1
(integer) 1
127.0.0.1:6379> getbit s 2
(integer) 1
127.0.0.1:6379> getbit s 3
(integer) 0

“中”这个字直接 GET 返回的是16进制数据,将 e4b8ad 转换成二进制是 11100100 10111000 10101101 ,然后我们就可以使用 GETBIT 来验证是不是和我们手动转换出来的是一样的结果。

大家有兴趣的可以再多了解一下字符编码相关的知识,比如在 Redis 中使用的 UTF8 ,为什么单个字节第一位只能是 0 ,必须是 0xxxxxxx 这样的,中文也都是固定的 1110xxxx 10xxxxxx 10xxxxxx 这种格式,很有意思哦。

位操作

既然是位操作,那么 与、或、异或、非 操作肯定要有啦。

127.0.0.1:6379> bitop or dd b c
(integer) 1
127.0.0.1:6379> get dd
"o"
127.0.0.1:6379> bitop and dd b c
(integer) 1
127.0.0.1:6379> get dd
"K"
127.0.0.1:6379> bitop xor dd b c
(integer) 1
127.0.0.1:6379> get dd
"$"
127.0.0.1:6379> bitop not dd b
(integer) 1
127.0.0.1:6379> get dd
"\xb0"

查询第一个bit位位置

通过 BITPOS 命令,可以查询到指定的 key 中,第一个出现的位数据的位置。

127.0.0.1:6379> BITPOS a 1
(integer) 4
127.0.0.1:6379> BITPOS a 0
(integer) 0

第一条命令是查询第一个 1 出现的位置,第二条命令是查询第一个 0 出现的位置。它还有第二个参数,这个参数是一个偏移量,不过需要注意的是,它指的是字节的偏移量,不是位的偏移量。

127.0.0.1:6379> BITPOS d 1 0
(integer) 1
127.0.0.1:6379> BITPOS d 1 1
(integer) 9
127.0.0.1:6379> BITPOS d 1 2
(integer) -1

统计数量

BITCOUNT 可以统计指定 key 中 1 出现的次数。

127.0.0.1:6379> BITCOUNT d
(integer) 10
127.0.0.1:6379> BITCOUNT d 1 0 2
(error) ERR syntax error
127.0.0.1:6379> BITCOUNT d 1 0 1
(error) ERR syntax error
127.0.0.1:6379> BITCOUNT d 1 2
(integer) 5
127.0.0.1:6379> BITCOUNT d 0 2
(integer) 10
127.0.0.1:6379> BITCOUNT d 2 3
(integer) 0

它还有两个参数,同样也是字节偏移量和长度。

位域操作

位域这个东西我就不太懂了,只是给个例子,这一块深入学过 C 的同学应该会比较了解。

127.0.0.1:6379> setbit e 1 1
(integer) 0
127.0.0.1:6379> get e
"@"
127.0.0.1:6379> BITFIELD e incrby i5 100 1 get u4 0
1) (integer) 1
2) (integer) 4
127.0.0.1:6379> get e
"@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80"

Bitmap 经典例子

好了,Bitmap 的基本操作就是上面那些,介绍的比较简单,不过也确实都不复杂。但前提是要对二进制和进制之间的转换以及字符编码要有一定的了解。如果我们只是为了去显示字符串的位,那就有点大材小用了,其实 Bitmap 有个非常强悍的能力,也就是运用 BITCOUNT 去进行数据统计。

包括官网上给出的也是类似这样的例子,统计登录用户数。

最开始我们已经知道,一个 key 可以保存40多亿个位,那么我们可以把用户id当作位索引,然后某个用户今天登录了,就给它的位设置为 1 ,然后就可以 BITCOUNT 快速统计出今天有多少用户登录了系统,速度相当快哦。

127.0.0.1:6379> setbit user_login_20220509 100010 1
(integer) 0
127.0.0.1:6379> setbit user_login_20220509 25525 1
(integer) 0
127.0.0.1:6379> setbit user_login_20220509 8782 1
(integer) 0
127.0.0.1:6379> setbit user_login_20220509 9846526547 1
(error) ERR bit offset is not an integer or out of range
127.0.0.1:6379> setbit user_login_20220509 98465265 1
(integer) 0
127.0.0.1:6379> setbit user_login_20220509 399999999 1
(integer) 0
127.0.0.1:6379> setbit user_login_20220509 3999999999 1
(integer) 0
127.0.0.1:6379> setbit user_login_20220509 4294967295 1
(integer) 0
127.0.0.1:6379> setbit user_login_20220509 4294967296 1
(error) ERR bit offset is not an integer or out of range
127.0.0.1:6379> BITCOUNT user_login_20220509
(integer) 7

HyperLogLog

既然说到统计了,那么 HyperLogLog 这个操作类型就不得不提了。它是一种概率数据结构,用于计算唯一事物的集合数量。同时,它是以内存换精度的,也就是说,它能极大的节约内存,但是会有精度丢失的问题。最坏情况下,也就是内存占用最大的情况下,它也只需要 12K 的内存容量就可以存储非常巨大的数据量,精度的丢失会在 1% 以内。它也可以实现上面 Bitmap 中统计的例子,我们先来看看相关的操作命令。

127.0.0.1:6379> pfadd hll a b c d e f g
(integer) 1
127.0.0.1:6379> pfcount hll
(integer) 7
127.0.0.1:6379> pfadd hll a b c d e f g h i j k
(integer) 1
127.0.0.1:6379> pfcount hll
(integer) 11

PFADD 添加数据,PFCOUNT 获取数量。基本的操作命令就这两个,是不是无敌了。除了这两个外,还有一个合并的命令,类似于集合的并集操作。

127.0.0.1:6379> PFADD pfa a b c d e f
(integer) 1
127.0.0.1:6379> PFADD pfb d c a e g i
(integer) 1
127.0.0.1:6379> pfadd pfc b d f i l m n o
(integer) 1
127.0.0.1:6379> PFMERGE pfmerge pfa pfb pfc
OK
127.0.0.1:6379> pfcount pfmerge
(integer) 12

另外,它也是以 String 为基本存储类型的,所以用 GET 也能看到内容。

127.0.0.1:6379> get hll
"HYLL\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00Fm\x80I\xe8\x80L\"\x80D<\x848\x80B=\x80K\x83\x80B\xed\x84A\xfc\x8cG\x8e\x80Bm\x80BZ"

好了,接下来说下 HyperLogLog 和其它方式统计的对比,以下是网上找到的相关文章获取到的资料。

如果我们使用 SET 来进行基数统计,那么假设每一个元素的 32Bit(2^24 ≈ 1600万; 2^32 ≈ 42亿) , 假设存储1亿个不重复的元素那么我们需要 100 000 000 * 32 /8/1024/1024 ≈ 381MB。

如果我们用 Bitmap 来进行基数统计,每个元素对应一位(bit),假设我们存储1亿个不重复的元素那么我们需要 100 000 000 /8/1024/1024 ≈ 12MB。

然而我们使用 HyperLogLog ,一个键占用的内容空间是12KB,并且这个键可以处理海量数据。

它们三个都可以应用在统计不重复元素的场景:

  • HyperLogLog:海量数据,可以忍受 0.81% 误差的场景,其实大数据处理的时候都会有误差。

  • Bitmap:数据量不大,不能忍受误差,元素连续的(自增的用户主键id)。

  • SET:数据量不大,不能忍受误差,元素没有规律,并且需要返回实际的单个元素。

总结

今天的内容挺好玩吧,Bitmap 和 HyperLogLog 最常用的其实都是一个不重复数据统计的场景,但是又各有优势。在日常的工作中如果有类似的应用场景,完全就可以使用这两种数据操作来试试了。

扩展知识:布隆过滤器

布隆过滤器(Bloom Filter),听说过没?面试有没有被坑过?跟你说,布隆过滤器的基础知识就是 Bitmap ,HyperLogLog 也是它的类似实现之一。啥叫布隆过滤器?就是能够快速地查找某一个元素是否存在于指定的集合中,最典型的做法就是使用二进制位来进行操作,这不就是 Bitmap 嘛。

当然,完整的布隆过滤器的实现还是要更复杂一些,它一般会有三个 Hash 函数,生成三个不同位置,只有当三个位置全部命中时,才会认为指定的数据已经存在。从这一点上来说,其实就是在有限的空间内可以存放更多的数据。但它也会出现不同的数据三个 Hash 函数计算结果一致的概率,但我们可以增加更多的 Hash 函数,不过相应地性能也会降低。同样,它也会有精度问题,反正大概原理就是这样。布隆过滤器有一个非常经典的名言,那就是“我说你不在,那你一定不在;我说你存在,你有可能存在(也可能不存在)!”。在 packgist 上也能搜到纯 PHP 实现布隆过滤器的 Composer 包,大家可以自己下载源码学习一下哦!

相关文章:

【Redis07】Redis基础:Bitmap 与 HyperLogLog 相关操作

Redis基础学习&#xff1a;Bitmap 与 HyperLogLog 相关操作继续进行 Redis 基础部分的学习&#xff0c;今天我们学习的是两种另外的数据类型。说是数据类型&#xff0c;但其实它们实际上使用的都是 String 类型做为底层基础&#xff0c;只不过是在存储的时候进行了一些特殊的操…...

华为路由器 VRRP主备配置

组网需求 如下图所示&#xff0c;PC1通过SW1双归属到R1和R2。为保证用户的各种业务在网络传输中不中断&#xff0c;需在R1和R2上配置VRRP主备备份功能。 正常情况下&#xff0c;主机以R1为默认网关接入Internet&#xff0c;当R1故障时&#xff0c;R2接替R1作为网关继续进行工作…...

docker容器安装ES

1.拉取镜像 docker pull elasticsearch:6.5.42.修改别名 docker tag [容器ID] es65:6.5.42.启动应用 docker run -it -d -p 9200:9200 -p 9300:9300 --name es -e ES_JAVA_OPTS"-Xms128m -Xmx128m" es65:6.5.43.拷贝配置文件到宿主机 docker cp es:/usr/share/ela…...

Python Module — prompt_toolkit CLI 库

目录 文章目录目录prompt_toolkit示例化历史记录热键自动补全多行输入Python 代码高亮自定义样式prompt_toolkit prompt_toolkit 是一个用于构建 CLI 应用程序的 Python 库&#xff0c;可以让我们轻松地构建强大的交互式命令行应用程序。 自动补全&#xff1a;当用户输入命令…...

springboot mybatis-plus 调用 sqlserver 的 存储过程 返回值问题

问题&#xff1a; 在使用 mybatis-plus 调用sqlserver 存储过程 没有返回值 经过资料查找 注意点 此处使用Map传参&#xff0c;原因在于存储过程的返回值&#xff0c;通常在参数定义中实现&#xff0c;如In 入参、out 出参。 这样当执行后有结果返回时&#xff0c;则可以将结…...

【0180】PG内核读取pg_hba.conf并创建HbaLine记录(1)

文章目录 1. pg_hba.conf文件是什么?2. postmaster何时读取pg_hba.conf?2.1 pg内核使用pg_hba.conf完成客户端认证的原理2.2 读取pg_hba.conf的几个模块3. pg内核读取pg_hba.conf过程3.1 VFD机制获取文件描述符3.2 根据fd读取文件内容相关阅读: 【0178】DBeaver、pgAdmin I…...

【原型设计工具】​​上海道宁为您提供Justinmind,助力您在几分钟内形成原型,并现场测试,无需编写任何代码

Justinmind是用于 Web和应用程序的原型制作工具 在几分钟内形成原型 并在现场进行测试 无需编写任何代码 单击一下即可轻松在线获取您的设计 并与整个团队共享 享受高效的沟通和快速反馈 以实现持续改进和利益相关者的支持 开发商介绍 JustinMind是由西班牙JustinMind公…...

计算机网络中---HDLP协议和PPP协议

目录 HDLC协议PPP协议HDLC协议和PPP协议HDLC协议 HDLC协议【高级数据链路控制协议】是一种数据链路层协议,用于在两个节点之间传输数据。以下是HDLC协议的重点知识: HDLC协议定义了一种标准的帧格式,包括起始标志、地址字段、控制字段、信息字段、校验字段和结束标志。HDLC…...

k8s之节点kubelet预留资源配置

k8s之kubelet预留资源配置1 前言2 预留资源Kube-reservedSystem-reservedEviction Thresholds实施节点可分配约束3 Pod优先级4 生产应用配置文件重启kubelet服务查看节点资源1 前言 最近k8s在使用过程中遇到这样一个问题 由于Pod没有对内存及CPU进行限制&#xff0c;导致Pod在…...

机器学习笔记之前馈神经网络(四)反向传播算法[数学推导过程]

机器学习笔记之前馈神经网络——反向传播算法[数学推导过程]引言回顾&#xff1a;感知机算法非线性问题与多层感知机反向传播算法(BackPropagation,BP\text{BackPropagation,BP}BackPropagation,BP)场景构建求解各权重更新量图示描述反向传播过程总结引言 上一节介绍了M-P\tex…...

vscode+elementui校园跑腿系统 nodejs+vue

本系统从用户的角度出发&#xff0c;结合当前的校园环境而开发的&#xff0c;在开发语言上是使用的Java语言&#xff0c;在框架上我们是使用的Vue框架&#xff0c;数据库方面使用的是MySQL数据库&#xff0c;开发工具为IDEA。 基于Vue的校园跑腿管理系统中的管理员配送用户都可…...

[蓝桥杯单片机8]定时器的简单应用

1、本实验内容 利用51单片机的定时/计数器T0的模式1实现间隔定时&#xff0c;每隔1秒L1指示灯闪烁一下&#xff0c;也就是点亮0.5秒&#xff0c;熄灭0.5秒&#xff1b;每隔2秒L8指示灯闪烁一下&#xff0c;即点亮1秒&#xff0c;熄灭1秒。2、基础知识 定时/计数器&#xff0c;是…...

node-HTTP协议

文章目录一. 概念二. 请求报文的组成三.HTTP请求行四.HTTP请求头五.HTTP的请求体六.响应报文的组成七.创建HTTP服务八.获取HTTP请求报文九.HTTP设置响应十.GET和POST请求的区别一. 概念 HTTP协议. 中文叫超文本传输协议; 是一种基于TCP/IP的应用层通信协议; 这个协议详细规定了…...

基于springboot+vue的地方美食分享网站

081-springboot基于vue的地方美食分享网站开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&am…...

【Android】之【Aplication】

一、Application简介 Application和Activity&#xff0c;Service一样是Android框架的一个系统组件&#xff0c;当Android程序启动时系统会创建一个Application对象&#xff0c;用来存储系统的一些信息。 Android系统自动会为每个程序运行时创建一个Application类的对象且只创建…...

社区之声|Grant Program支持Moonbeam生态壮大

在本次社区之声会议中&#xff0c;Moonbeam基金会解释生态系统Grant流程、一个由社区成员组成的圆桌讨论表达各自对此次Grant的看法&#xff0c;Moonbeam开发者关系工程师演示了如何在Snapshot对申请生态系统Grant项目的投票。观看视频回顾 请注意&#xff0c;内容仅供参考&am…...

GO实现Redis:GO实现Redis协议解析器(2)

本文实现Redis的协议层&#xff0c;协议层负责解析指令&#xff0c;然后将指令交给核心database执行echo database用来测试协议层的代码https://github.com/csgopher/go-redis RESP协议 RESP是客户端与服务端通信的协议&#xff0c;格式有五种&#xff1a;正常回复&#xff1…...

Geoserver 发布wmts服务,以及cesium加载发布的wmts服务

WMTS提供了一种采用预定义图块方法发布数字地图服务的标准化解决方案。WMTS弥补了WMS不能提供分块地图的不足。WMS针对提供可定制地图的服务&#xff0c;是一个动态数据或用户定制地图&#xff08;需结合SLD标准&#xff09;的理想解决办法。WMTS牺牲了提供定制地图的灵活性&am…...

【微信小程序】selectComponent(#id)失败得到是null分析

小程序中无法像网页中轻易的获取DOM元素&#xff0c;需要依靠 this.selectComponent(#id)this.selectAllComponents(#id) 本文主要针对 this.selectComponent 获取DOM元素失败的原因 下面开始正文 上图为我的业务代码&#xff0c;由图可知&#xff0c;通过for循环遍历渲染ca…...

JVM中引用计数法与可达性分析

目录 概要 如何判断对象已死&#xff1f; 引用计数算法 优点 缺点 举例说明 可达性分析 图例说明 GC Roots的对象包括以下几种 可达性分析回收过程 四大引用 回收方法区 方法区的垃圾收集主要回收两部分内容&#xff1a; 1. 废弃的常量 2. 不再使用的类型。 JVM是…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...