Btree并发内存回收
在并发写Btree原理剖析 一文中提到,节点内存回收有可能导致内存突增以及影响写性能。本文将阐述最近对内存回收的改进,多线程可并行回收内存。
回收策略
采用基于版本的机制,Btree全局维护一个版本号V,一个全局数组A,每个线程一个槽位,每个线程读写操作之前获取全局版本号V,记作V0,并且记录到全局数组A中自己所属的槽位,表明对应线程不会再访问版本号V0之前的节点。写操作结束后,获取全局版本号V记录到这次写操作的TRecycleNode中,然后将V原子加1,这样来推进Btree的版本号递增,最后将这个TRecycleNode挂在线程局部的TRecycleNode的链表尾部。回收内存时,只需要遍历全局数组A,找到最小版本号记作minV,每个线程只回收线程局部的版本号小于minV的所有的TRecycleNode及其内部的TBtreeNode。可以看出,在目前这种回收策略中,不存在全局的TRecycleNode链表,线程不用抢锁,各自回收自己局部内存即可。
这里有一个问题:如果某个线程由于某些原因,很少对Btree进行读写,那么全局数组A的最小值永远不变,导致其他线程也不能回收内存。针对这种情况,可以在每次读写操作结束后,将线程在全局数组中对应的槽位置为无穷大。
这就带来了另外一个问题:一个线程刚拿到全局版本号V,记作V0,还没有来得及放入全局数组A对应槽位,随后一些写操作完成全局版本号V被递增,然后某个线程开始回收,扫描了全局数组并且已经计算出了最小版本V1,这时V1 > V0, 代表V0可以被回收,这时,第一个线程读V0就会出现问题。解决这个问题,可以使用类似于hazard pointer的机制,读写开始获取版本号和获取回收版本号的过程分别如下:
读写开始拿可用版本号的过程:
1. 拿全局版本号V放入局部变量V0: V0 <- V
2. 将V0写入全局数组中对应的槽位中: A[slot] <- V0
3. 如果 V0 = V 则可以开始安全的读写,版本号为V0,否则重试,跳第一步。
写线程回收时拿到可回收版本号的过程:
1. 拿全局版本号V放入局部变量V1: V1 <- V
2. V2 <- min(A)
3. V3 <- min(V1,V2) V3之前的版本即为可以回收的版本
证明:
1. 如果V1 <= V0:则V3 = min(V1,V2) <= V1 <= V0,读写拿到的版本号V0 大于等于回收版本号
2. 如果V1 > V0:如果读写过程的第三步成立V0 = V,那么,回收过程的第二步V2 <- min(A)计算最小值时已经看到了读写过程写入全局数组A中的版本V0,即V3 = min(V1,V2) <= V0
可以看出,这种方式对于正常的Btree读写流程来说,可能第3步需要进行重试: 在第一步和第三步之间的最多的几十ns期间全局版本号V被其它写线程递增。当然,这种情况还算是比较少。为了进一步的避免这个问题,可以采用如下方法:
维护一个全局可回收版本号recycleV,它比V小一些,比如100个版本,每个线程回收时只会回收小于recycleV的TRecycleNode,读写过程和回收过程算法如下:
读写开始拿可用版本号的过程:
1. 拿全局版本号V放入局部变量V0: V0 <- V
2. 将V0写入全局数组中对应的槽位中: A[slot] <- V0
3. 如果 V0 > recycleV 则可以开始安全的读写,版本号为V0,否则重试,跳第一步。
写线程回收时拿到可回收版本号的过程:
1. recycleV <- V – 100 多线程需要保证recycleV递增
2. V2 <- min(A)
3. V3 <- min(recycleV,V2) 小于V3的版本即为可以回收的版本
这种优化相当于让回收线程滞后100个版本回收。
还有其它一些小优化,比如全局数组A每个元素cache line对齐,避免false sharing,线程局部可用节点太多,归还一些到全局内存池等。
分析
从读写操作开始拿版本号的过程可以看出,实际上这种方法就是hazard pointer !! 看这篇:lock free数据结构内存回收技术-hazard pointer
读写开始拿可用版本号的过程:
1. 拿全局版本号V放入局部变量V0: V0 <- V
2. 将V0写入全局数组中对应的槽位中: A[slot] <- V0 // 这一步相当于将pointer给保护起来
3. 如果 V0 > recycleV 则可以开始安全的读写,版本号为V0,否则重试,跳第一步。 // 这一步相当于check一下上一步是否保护成功
测试结果
在2路超线程32core机器上,起32个线程,int64_t作为KV,TPS由原来的120W左右提升到240W左右,QPS由原来的680W左右提升到1900W左右。
Btree并发内存回收的更多相关文章
- 4、jvm内存回收——器
内存回收---->垃圾回收---->GC GC 三基础,一个综合G1 串行:单线程,回收暂停其他 并行:多线程,回收暂停其他 并发:多线程,回收不暂停?! 成功好说,失败Serial Ol ...
- JVM内存回收机制简述
JVM内存回收机制涉及的知识点太多了,了解越多越迷糊,汗一个,这里仅简单做个笔记,主要参考<深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)> 目前java的jdk默认虚拟机为H ...
- Java内存回收机制
在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C/C++直接操作内存的危险.但是,也正 ...
- Java的内存回收机制
原文出处: cnblogs-小学徒V 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C ...
- [转载]Java的内存回收机制
转自:http://www.admin10000.com/document/1671.html 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由J ...
- JVM中内存回收深入分析,各种垃圾收集器
JVM启动有两种模式,client和server 一般JVM启动时会根据主机情况分析选择采用那种模式启动 可发现是server模式 JVM中尤其需要关注的就是HEAP堆区 堆区分为新生代和老年代 新生 ...
- 《深入理解Java虚拟机》学习笔记之内存回收
垃圾收集(Garbage Collection,GC)并不是Java语言的半生产物,事实上GC历史远比Java久远,真正使用内存动态分配和垃圾收集技术的语言是诞生于1960年的Lisp语言.经过半个世 ...
- JVM(三)内存回收(一)
最近花了相当长一段时间在看Hotspot JVM的GC和内存分配,本节先总结和回顾一下内存回收的相关知识点,内存的分配放到下节再讨论. 一.什么是JVM的GC GC即Garbage Collectio ...
- JVM(四)内存回收(二)
在上一节中"JVM(三)内存回收(一)"我讲到了垃圾回收的几种算法,算是解决了之前提到的3个问题中的最后一个. 关于内存回收,还应该了解常用的内存回收器(GC Collector) ...
随机推荐
- jetbrains golang IDE
非常好的IDE,叫goland. 支持最新的golang1.8了 下载地址: https://www.jetbrains.com/go/ 开始使用手册: https://www.jetbrains.c ...
- 编写Android工程里测试代码的步骤
第一步: 写个类去继承 AndroidTestCase public class TestStudent extends AndroidTestCase 并且编写一个测试的方法, 注意,测试的方法必须 ...
- mysql 数据库自动备份
@echo offset "Ymd=%date:~,4%%date:~5,2%%date:~8,2%""E:/MySQL/MySQL Server 5.7/bin/mys ...
- Android 开发工具类 16_NotificationActivity
在前台运行的 Activity 可以通过Dialog.Toast 向用户发出提示信息,而后台运行的程序,如下载.收到信息等 Service 应用,则需要使用 Notification(通知)向用户发出 ...
- Disconf 学习系列之全网最详细的最新稳定Disconf 搭建部署(基于Ubuntu14.04 / 16.04)(图文详解)
不多说直接上干货! https://www.cnblogs.com/wuxiaofeng/p/6882596.html (ubuntu16.04) https://www.cnblogs.com/he ...
- 笔记三:python乱码深度剖析一
一:学习内容 python编码转换 python乱码原因深入解析 二:python编码转换 1. Python内部字符串一般都是Unicode编码,代码中字符串的默认编码与代码文件本身的编码是一致的. ...
- 8分钟丨教你玩转 API
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由织云平台团队发表于云+社区专栏 背景 当下,业界越来越多公司在项目架构设计时,会采用微服务架构.微服务架构,可以让我们的产品有更好的扩 ...
- redis实战笔记(6)-第6章 使用 Redis构建应用程序组件
本章主要内容 1.构建两个前缀匹配自 动补全程序 2.通过构建分布式锁来提高性能 3.通过开发计数信号量来控制并发 4.构建两个不同用途的任务队列 5.通过消息拉取系统来实现延迟消息传递 6.学习 ...
- [转]File uploads in ASP.NET Core
本文转自:https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads By Steve Smith ASP.NET MVC ...
- DOM-添加元素、节点
createElement()方法能够根据参数指定的标签名称创建一个新元素,并返回新建元素的引用,用法如下 var element=document.createElement("tagNa ...