字符串对象
字符串对象的编码可以是int、raw或者embstr
如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面(将void *转换成long),并且将字符串对象的编码设置为int
举个例子,如果执行以下SET命令,那么服务器将创建一个如图所示的int编码的字符串对象作为number键的值:
127.0.0.1:6379> SET number 10086
OK
127.0.0.1:6379> OBJECT ENCODING number
"int"
如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于(3.2版本之前是39字节,之后变成44字节,后面再分析),那么字符串对象将使用简单动态字符串(SDS)来保存这个字符串,并将对象的编码设置为raw.举个例子,如果执行以下命令,那么服务器将创建一个如图所示的字符串对象作为story键的值:
127.0.0.1:6379> SET stroy "Long, long, long, ago, there, lived, a, king, 123456789987654321"
OK
127.0.0.1:6379> STRLEN stroy
(integer) 65
127.0.0.1:6379> OBJECT ENCODING stroy
"raw"
如果字符串对象的保存的是一个字符串值,并且这个字符串值的长度小于等于(39或44字节),那么字符串对象将使用embstr编码的方式来保存这个字符串值。embstr编码是专门用于保存短字符串的一种优化编码方式,
这种编码和raw编码一样,都是用redisObject结构和sdshdr结构来表示字符串对象,但raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配
一块连续的空间,空间中依次包含redisObject和sdshdr两个结构,如图所示。
embstr编码的字符串对象在执行命令时,产生的效果和raw编码的字符串对象执行命令时产生的效果时相同的,但使用eembstr编码将创建字符串对象来保存短字符串值有以下好处:
- 1.embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降低为一次。
+2.释放embstr编码的字符串对象只需要调用一次内存释放函数,而释放raw编码的字符串对象需要调用两次内存释放函数 - 3.因为embstr编码的字符串对象的所有数据都保存在一块连续的内存里面,所以这中编码的字符串对象比起raw编码的字符串对象比起raw编码的字符串对象能够更好地利用缓存带来的优势。
举个例子,以下命令创建了一个embstr编码的字符串对象作为msg键的值,值对象的样子,
127.0.0.1:6379> SET msg "hello"
OK
127.0.0.1:6379> OBJECT ENCODING msg
"embstr"
还可以用long double类型表示的浮点数在Redis中也是作为字符串值来保存的。如果要保存一个浮点到字符串对象里面,那么程序会先将这个f浮点数转换成字符串值,然后再保存转换所得的字符串值。
举个例子,执行以下代码将创建一个包好3.14的字符串表示"3.14"的字符串对象:
127.0.0.1:6379> SET pi 3.14
OK
127.0.0.1:6379> OBJECT ENCODINg pi
"embstr"
在有需要的时候,程序会将保存在字符串对象里面的字符串值转换回浮点数值,执行某些操作,然后再将执行操作所得的浮点数值转换回字符串值,并继续保存在字符串对象里面.
举个例子,如果执行以下代码:
127.0.0.1:6379> INCRBYFLOAT pi 2.0
"5.140000000000001"
127.0.0.1:6379> OBJECT ENCODING pi
"embstr"
那么程序首先会取出字符串对象里面保存的字符串值"3.14",将它转化回浮点数值3.14,然后再把3.14和2.0相加得出的值
5.14转换成字符串"5.14",并将这个"5.14"保存到字符串对象里面。
编码的转换
int编码的字符串对象和embstr编码的字符串对象在条件满足的情况下,会被转换为raw编码的对象。对于int编码的字符串对象来说,如果向对象执行了一些命令,使得这个对象保存的不再是整数值,而是一个字符串值。那么字符串对象的编码将从int变为raw.
另外,因为Redis没有为embstr编码的字符串对象编写任何相应的修改程序(只有int编码的字符串对象和raw编码的字符串对象有这些程序),所以embstr编码的字符串对象实际上是只读的。当对embstr编码的字符串对象执行任何修改命令时,程序会先将对象的编码从embstr转换成raw,然后再执行修改命令。因为这个原因,embstr编码的字符串对象在执行修改命令之后,总会变成一个raw编码的字符串对象。
举个例子,通过APPEND命令,向一个保存整数值的字符串对象追加了一个字符串值,因为追加操作只能对字符串值执行,所以程序会先将之前保存的整数值10086转换为字符串值"10086",然后再执行追加操作,操作的执行结果就是一个raw编码的、保存了字符串值的字符串对象
127.0.0.1:6379> SET number 10086
OK
127.0.0.1:6379> OBJECT ENCODING number
"int"
127.0.0.1:6379> APPEND number " is a good number!"
(integer) 23
127.0.0.1:6379> GET number
"10086 is a good number!"
127.0.0.1:6379> OBJECT ENCODING number
"raw"
以下代码展示了一个embstr编码
127.0.0.1:6379> SET msg "hello world"
OK
127.0.0.1:6379> OBJECT ENCODING msg
"embstr"
127.0.0.1:6379> APPEND msg " again!"
(integer) 18
127.0.0.1:6379> OBJECT ENCODING msg
"raw"