Android ART GC -- AtomicStack 无锁原子栈的实现分析
来源:互联网 发布:python 自动化发邮件 编辑:程序博客网 时间:2024/05/06 17:26
在android ART GC 中类AtomicStack用来实现对象的栈,如下:
typedef AtomicStack<mirror::Object*> ObjectStack;
ObjectStack用来实现android ART GC中三个最重要的栈,即mark_stack_,allocation_stack_,live_stack,对于这三个栈的详细分析见 :
Android ART GC --mark_stack_,allocation_stack_,live_stack_
在模板类AtomicStack中实现了栈的一些基本操作,包括入栈、出栈等。同时,也利用C++11的原子操作实现了无锁栈(lock-free stack),提高了栈的性能。
模板类AtomicStack的定义如下(art/runtime/gc/accounting/atomic_stack.h):
template <typename T>class AtomicStack { public: static AtomicStack* Create(const std::string& name, size_t growth_limit, size_t capacity); ~AtomicStack() {} void Reset(); bool AtomicPushBackIgnoreGrowthLimit(const T& value); bool AtomicPushBack(const T& value); bool AtomicBumpBack(size_t num_slots, T** start_address, T** end_address); void AssertAllZero(); void PushBack(const T& value); T PopBack(); T PopFront(); void PopBackCount(int32_t n); bool IsEmpty(); size_t Size(); T* Begin(); T* End(); size_t Capacity(); void Resize(size_t new_capacity); void Sort(); bool ContainsSorted(const T& value); bool Contains(const T& value); private: AtomicStack(const std::string& name, size_t growth_limit, size_t capacity) : name_(name), back_index_(0), front_index_(0), begin_(nullptr), growth_limit_(growth_limit), capacity_(capacity), debug_is_sorted_(true) { } bool AtomicPushBackInternal(const T& value, size_t limit); void Init(); std::string name_; std::unique_ptr<MemMap> mem_map_; AtomicInteger back_index_; AtomicInteger front_index_; T* begin_; size_t growth_limit_; size_t capacity_; bool debug_is_sorted_;};
可以看到模板类AtomicStack实现了栈的一些操作,并且是基于std::atomic的原子操作,这是C++11的新标准。所谓的原子操作,就是确保了在同一时刻只有唯一的线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。
============================================================================
name_是栈的名字,mem_map_是栈的内存映射的一个unique_ptr智能指针,back_index_和front_index_是原子操作的栈顶(最后入栈对象的下一个空间)和栈底的索引,类型为AtomicInteger,begin_是这个原子栈的基址,growth_limit_是当前栈的最大可允许增加对象数,capacity_是栈的最大可容纳对象数,debug_is_sorted_用来在调试时对栈是否排序进行设定。
其中AtomicInteger如下:
typedef Atomic<int32_t> AtomicInteger;
下面来看下模板类AtomicStack的公有成员函数的实现,其中包括如何实现栈的一些基本操作。
1.
static AtomicStack* Create(const std::string& name, size_t growth_limit, size_t capacity) { std::unique_ptr<AtomicStack> mark_stack(new AtomicStack(name, growth_limit, capacity)); mark_stack->Init(); return mark_stack.release(); }Create实现了创建一个标记栈的方法,标记栈在gc的mark阶段用来加速递归标记。
2.
void Reset() { DCHECK(mem_map_.get() != nullptr); DCHECK(begin_ != NULL); front_index_.StoreRelaxed(0); back_index_.StoreRelaxed(0); debug_is_sorted_ = true; mem_map_->MadviseDontNeedAndZero(); }Reset把栈复位,包括栈顶、栈底索引的置0,栈所映射的内存的置0。
其中
front_index_.StoreRelaxed(0);用到了模板类Atomic中的方法。
模板类Atomic在art/runtime/atomic.h中定义:
template<typename T>class PACKED(sizeof(T)) Atomic : public std::atomic<T> {..}
所以模板类是继承了atomic的。
而StoreRelaxed()如下:void StoreRelaxed(T desired) { this->store(desired, std::memory_order_relaxed);}
调用std::atomic::store()进行存储值的替换.
3.
原子操作的入栈
bool AtomicPushBackIgnoreGrowthLimit(const T& value) { return AtomicPushBackInternal(value, capacity_); }
bool AtomicPushBack(const T& value) { return AtomicPushBackInternal(value, growth_limit_); }调用类的私有成员函数AtomicPushBackInternal()进行入栈操作。
bool AtomicPushBackInternal(const T& value, size_t limit) ALWAYS_INLINE { if (kIsDebugBuild) { debug_is_sorted_ = false; } int32_t index; do { index = back_index_.LoadRelaxed(); if (UNLIKELY(static_cast<size_t>(index) >= limit)) { // Stack overflow. return false; } } while (!back_index_.CompareExchangeWeakRelaxed(index, index + 1)); begin_[index] = value; return true; }在runtime/base/macros.h中定义了ALWAYS_INLINE,表示这是一个内联函数:
#define ALWAYS_INLINE __attribute__ ((always_inline))
此私有成员函数涉及两个关于模板类Atomic的操作:
T LoadRelaxed() const { return this->load(std::memory_order_relaxed); }std::atomic::load用来装载存储值。
bool CompareExchangeWeakRelaxed(T expected_value, T desired_value) { return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_relaxed); }std::atomic::compare_exchange_weak,
可以参考http://blog.csdn.net/anzhsoft/article/details/19125619对CAS原子操作的讲解。
关键在于理解
back_index_.CompareExchangeWeakRelaxed(index, index + 1)
(1)如果back_index_存储的值等于index,那么back_index_存储的值就等于index+1,并且返回true,也就跳出while循环,然后用begin_[index]=value完成入栈操作,此时back_index_也已经更新为index+1了。
(2)否则,index就等于back_index_存储的值(在此处似乎没什么用?因为do while中又对index进行了更新),返回false,说明有其他线程对栈进行了修改,然后更新index,继续循环,直到原子入栈操作完成。
4.
// Atomically bump the back index by the given number of // slots. Returns false if we overflowed the stack. bool AtomicBumpBack(size_t num_slots, T** start_address, T** end_address) { if (kIsDebugBuild) { debug_is_sorted_ = false; } int32_t index; int32_t new_index; do { index = back_index_.LoadRelaxed(); new_index = index + num_slots; if (UNLIKELY(static_cast<size_t>(new_index) >= growth_limit_)) { // Stack overflow. return false; } } while (!back_index_.CompareExchangeWeakRelaxed(index, new_index)); *start_address = &begin_[index]; *end_address = &begin_[new_index]; if (kIsDebugBuild) { // Sanity check that the memory is zero. for (int32_t i = index; i < new_index; ++i) { DCHECK_EQ(begin_[i], static_cast<T>(0)) << "i=" << i << " index=" << index << " new_index=" << new_index; } } return true; }与AtomicPushBackInternal()相似,只是返回栈中指定入栈对象个数时的起始地址和结束地址。
5.
非原子操作的入栈、出栈,很好理解
void PushBack(const T& value) { if (kIsDebugBuild) { debug_is_sorted_ = false; } int32_t index = back_index_.LoadRelaxed(); DCHECK_LT(static_cast<size_t>(index), growth_limit_); back_index_.StoreRelaxed(index + 1); begin_[index] = value; } T PopBack() { DCHECK_GT(back_index_.LoadRelaxed(), front_index_.LoadRelaxed()); // Decrement the back index non atomically. back_index_.StoreRelaxed(back_index_.LoadRelaxed() - 1); return begin_[back_index_.LoadRelaxed()]; } // Take an item from the front of the stack. T PopFront() { int32_t index = front_index_.LoadRelaxed(); DCHECK_LT(index, back_index_.LoadRelaxed()); front_index_.StoreRelaxed(index + 1); return begin_[index]; }6.
弹出指定个数的对象,只更新栈顶
// Pop a number of elements. void PopBackCount(int32_t n) { DCHECK_GE(Size(), static_cast<size_t>(n)); back_index_.FetchAndSubSequentiallyConsistent(n); }
T FetchAndSubSequentiallyConsistent(const T value) { return this->fetch_sub(value, std::memory_order_seq_cst); // Return old value. }调用std::atomic::fetch_sub使back_index减n。
7.
一些栈的基本信息的输出
bool IsEmpty() const { return Size() == 0; } size_t Size() const { DCHECK_LE(front_index_.LoadRelaxed(), back_index_.LoadRelaxed()); return back_index_.LoadRelaxed() - front_index_.LoadRelaxed(); } T* Begin() const { return const_cast<T*>(begin_ + front_index_.LoadRelaxed()); } T* End() const { return const_cast<T*>(begin_ + back_index_.LoadRelaxed()); } size_t Capacity() const { return capacity_; } // Will clear the stack. void Resize(size_t new_capacity) { capacity_ = new_capacity; growth_limit_ = new_capacity; Init(); }
8.
调用std::sort进行快速排序,性能可能比较差。
void Sort() { int32_t start_back_index = back_index_.LoadRelaxed(); int32_t start_front_index = front_index_.LoadRelaxed(); std::sort(Begin(), End()); CHECK_EQ(start_back_index, back_index_.LoadRelaxed()); CHECK_EQ(start_front_index, front_index_.LoadRelaxed()); if (kIsDebugBuild) { debug_is_sorted_ = true; } }9.
搜索
bool ContainsSorted(const T& value) const { DCHECK(debug_is_sorted_); return std::binary_search(Begin(), End(), value); }
10.
查找
bool Contains(const T& value) const { return std::find(Begin(), End(), value) != End(); }11.
初始化
void Init() { std::string error_msg; mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), PROT_READ | PROT_WRITE, false, &error_msg)); CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg; uint8_t* addr = mem_map_->Begin(); CHECK(addr != NULL); debug_is_sorted_ = true; begin_ = reinterpret_cast<T*>(addr); Reset(); }
参考:
【1】http://blog.csdn.net/anzhsoft/article/details/19125619 并发编程(三): 使用C++11实现无锁stack(lock-free stack)
- Android ART GC -- AtomicStack 无锁原子栈的实现分析
- Android ART GC之GrowForUtilization的分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- CAS原子操作实现无锁及性能分析
- Android内存优化(二)DVM和ART的GC日志分析
- Android Art 虚拟机 GC 机制之 java 部落的崛起
- C++原子性实现无锁队列
- 用原子操作实现无锁编程
- 如何测试移动端App
- iOS_模拟器定位
- 线性代数-向量空间-基向量定义
- Oracle/SQL 修改字段类型和长度
- Jboss 安全和优化
- Android ART GC -- AtomicStack 无锁原子栈的实现分析
- c函数返回指针
- Spring实例化Bean的三种方式
- FreeBSD 安装axel提高ports的安装速度
- TableView的属性和方法
- iOS之UIDatePicker
- cocos2dx VS中 添加lib项目方法
- 二叉查找数
- 判断自己的应用是否在前台运行