关于垃圾回收机制:Datenlord-垃圾回收机制与无锁化编程二
上一篇文章介绍了无锁化编程场景下的一种垃圾回收机制,Epoch-based Memory Reclaimation(EB)。 本篇介绍另一种无锁化编程场景下的垃圾回收机制,Hazard Pointer(HP)。HP也是一种确定型GC。 HP的内存回收办法比较简单: 对无锁化编程场景下的每个线程,须要显式标注出该线程要竞争拜访的共享对象,即线程把要竞争拜访的对象的指针标注为危险指针(Hazard Pointer), 拜访完结后或勾销标注该危险指针、或标注该危险指针指向的共享对象为待回收。 在回收内存时,HP判断每个待回收的共享对象是否能够平安回收,只须要查看该对象的指针是否正被某个线程标注为危险指针,如果没有就能回收,否则不能回收。 HP跟EB一样也是采纳空间换工夫的策略,并不是马上回收每个能够被回收的共享对象,而是批量回收,以缩小内存回收对程序性能的影响。 确定型GC算法Hazard Pointer(HP)持续沿用无锁化堆栈作为例子来展现HP的用法,而后再介绍HP的细节。 Hazard Pointer(HP)的用法采纳HP作为GC的无锁化堆栈的入栈和出栈操作实现如下所示。 struct Node { void* data; std::atomic< Node * > next;};std::atomic<Node *> top; // 栈顶top.store( nullptr ); // 初始化栈顶为空指针bool push( Node* new_node ) { // 线程本地的危险指针队列里新增一个危险指针 HP * hazard_cur_top = LocalHP::new_hp(); while ( true ) { Node * cur_top = top.load(); // 标注以后栈顶指针cur_top为危险指针 hazard_cur_top.set(cur_top); new_node->next.store( cur_top ); // CAS调用批改栈顶 if ( top.compare_exchange_weak( cur_top, new_node )) { break; // 批改栈顶胜利 } } // 入栈操作胜利,勾销标注cur_top为危险指针 hazard_cur_top.set(nullptr); return true;}Node * pop() { // 线程本地的危险指针队列里新增两个危险指针 HP * hazard_cur_top = LocalHP::new_hp(); HP * hazard_next = LocalHP::new_hp(); while ( true ) { Node * cur_top = top.load(); if ( cur_top == nullptr ) { break; // 堆栈为空 } // 标注以后栈顶指针cur_top为危险指针 hazard_cur_top.set(cur_top); Node * next = cur_top->next.load(); // 标注以后栈顶的下一节点指针next为危险指针 hazard_next.set(cur_top); // CAS调用批改栈顶 if ( top.compare_exchange_weak( cur_top, next )) { break; // 批改栈顶胜利 } } if ( cur_top != nullptr ) { // 出栈操作胜利,标注cur_top为待回收对象 hazard_cur_top.maybe_reclaim(); } else { // 栈为空,勾销标注cur_top为危险指针 hazard_cur_top.set(nullptr); } // 出栈操作完结,勾销标注next为危险指针 hazard_next.set(nullptr); return cur_top;}下面的实现能够看出,入栈操作和出栈操作有不同的危险指针。对于入栈操作: ...