《redis设计与实现》_第二章_内存重分配

遗留问题
上一小节说到,sdscat函数不仅对SDS进行了拼接而且还为SDS分配了13字节的未使用空间,而拼接后的字符串恰好为13字节。这里涉及到了修改字符串的内存重分配的问题。
修改字符串的内存重分配次数
前提:C字符串长度为n则需要n+1个字符长的数组。
因为此前提,在每次修改C字符串时就需要对这个数组进行一次内存重分配操作。
为什么要进行内存重分配?
1.如在拼接字符串时,如果数组空间不足,则会导致缓冲区溢出,在执行拼接之前,先进行内存重分配,则可以避免此问题。
2.如在截断字符串时,如果直接截断,则数组会产生无用的空间而无法释放,产生内存泄露。在截断之前,进行内存重分配释放掉数组不用的空间。
内存重分配的影响
1.复杂的算法
2.执行系统调用
所以这是一个耗时的操作。
Redis是用于速度要求严苛、数据频繁被使用的场景。如果修改一次字符串就要进行一次内存重分配,会对其性能产生恶劣的影响。
所以在Redis中需要减少内存重分配的次数。
SDS中的解决办法
进行内存重分配的原因就是C字符串长度和底层数组长度之间的关联。故以此为突破点来设计。
在SDS中buf数组长度不一定是字符串长度加一,因为数组里可以包含未使用的字节,free就可以记录。

主要有两种设计
空间预分配和惰性空间释放
空间预分配
用于SDS的字符串增长操作:当SDS的API对一个SDS进行修改并需要拓展空间时,程序不仅会分配修改所必要的空间,同时会分配额外未使用的空间。
在遗留问题中,就是因为空间预分配,SDS中会有13字节的未使用空间。
分配未使用空间数量公式:
1.若SDS长度(len)小于1mb,则程序分配和len属性同样大小的空间,这时,len==free。(遗留问题中分配13字节的原因)
2.若SDS长度(len)大于等于1mb,则程序分配1mb的未使用空间。如,进行修改之后,SDS的len将变成30mb,那么程序会分配1mb的未使用空间。数组实际长度为30mb+1mb+1byte。
空间预分配的好处
通过预分配策略,可以使SDS将连续增长n次字符串所需的内存重分配次数从必定n次减少为最多n次。
惰性空间释放
优化SDS的字符串缩短操作。当SDS的API需要缩短SDS保存的字符串长度,程序不会立即用内存重分配来回收缩短多出来的字节,而是用free来将这些字节数量记录下来,并等待使用。

这样当再次对字符串修改时,会有预留的空间,如果足够则不需再次进行内存重分配。
惰性空间释放造成内存浪费
SDS提供了相应的API可以真正释放未使用空间,故无需担心造成内存浪费。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Redis可以非常方便地实现排行榜功能。以下是一个使用Java实现Redis排行榜的示例代码: ```java import redis.clients.jedis.Jedis; import redis.clients.jedis.Tuple; import java.util.Set; public class RedisRankList { private Jedis jedis; private static final String RANK_LIST_KEY = "rank_list"; public RedisRankList() { jedis = new Jedis("localhost"); } public void addScore(String member, double score) { jedis.zadd(RANK_LIST_KEY, score, member); } public void removeMember(String member) { jedis.zrem(RANK_LIST_KEY, member); } public void incrementScore(String member, double increment) { jedis.zincrby(RANK_LIST_KEY, increment, member); } public Set<Tuple> getRankList() { return jedis.zrevrangeWithScores(RANK_LIST_KEY, 0, -1); } public static void main(String[] args) { RedisRankList rankList = new RedisRankList(); rankList.addScore("张三", 90); rankList.addScore("李四", 80); rankList.incrementScore("李四", 10); rankList.addScore("王五", 70); Set<Tuple> topScores = rankList.getRankList(); for (Tuple tuple : topScores) { System.out.println(tuple.getElement() + " : " + tuple.getScore()); } } } ``` 在上述示例代码中,我们使用了Jedis客户端连接到本地Redis服务器,并实现了添加成员分数、移除成员、增加成员分数、获取排行榜等功能。其中,`zadd`方法用于添加成员分数,`zrem`方法用于移除成员,`zincrby`方法用于增加成员分数,`zrevrangeWithScores`方法用于获取排行榜。通过运行该示例代码,我们可以得到以下结果: ``` 张三 : 90.0 李四 : 90.0 王五 : 70.0 ``` 可以看到,排行榜按照成员分数从高到低排序,且李四的分数已经增加了10分。这样,我们就成功地使用Java实现Redis排行榜功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值