art的bitmap使用

bitmap的原理

bitmap是一块内存,利用其中的每一位去标记对应的内存是否被使用,1为被使用,0位没有使用。

 

SpaceBitmap

art中使用SpacBitmap 对heap进行标记,我们看下spaceBitmap的重要逻辑

a. Creat函数初始化

-----------Create-------------------------------------------------

SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::Create(const std::string& name, uint8_t* heap_begin, size_t heap_capacity) {

    //bitmap_size(标记heap_capacity大小需要的 字节数)

    const size_t bitmap_size = ComputeBitmapSize(heap_capacity);

    |____________________ComputeBitmapSize ________________________________________________________________________________________________

    //理论上我们1个bit标记一个kAlignment大小字节的内存,而我们不能直接创建对象操作bit,这里利用intptr_t 和 uintptr_t数据类型。

    //标记的时候我们一般先找到内存对应bitmap所在的uintptr_t 对象位置,然后在针对uintptr_t对象进行按位操作。

    //这里这份size计算如下:capacity 代表标记的heap大小,单位是字节

    size_t SpaceBitmap<kAlignment>::ComputeBitmapSize(uint64_t capacity) {

        // kBitsPerIntPtrT代表一个intptr_t 数据类型占用多少位,32位平台是32,64位平台是64,kAlignment  kAlignment是bit标记的内存大小,

        //一般标记object 是8byte,而标记page是4byte。 假设64位平台标记object,一个intptr_t 对象可以标记8*64=512字节

        const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerIntPtrT; 

        //这个主要是对capacity 补位到kBytesCoveredPerWord 的整数倍,然后再属于intptr_t大小得到需要的bitmap大小。

        return  (RoundUp(capacity, kBytesCoveredPerWord) / kBytesCoveredPerWord) * sizeof(intptr_t);

    }

    |_______________________________________________________________________________________________________________________________________________

    //通过MapAnonymous创建一块内存给SpaceBitmap进行标记

    MemMap mem_map = MemMap::MapAnonymous(name.c_str(),bitmap_size,PROT_READ | PROT_WRITE,/*low_4gb=*/ false,&error_msg);

    return CreateFromMemMap(name, std::move(mem_map), heap_begin, heap_capacity);

}

template<size_t kAlignment>

SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::CreateFromMemMap(const std::string& name, MemMap&& mem_map, uint8_t* heap_begin, size_t heap_capacity) {

    uintptr_t* bitmap_begin = reinterpret_cast<uintptr_t*>(mem_map.Begin());

    const size_t bitmap_size = ComputeBitmapSize(heap_capacity);

    //我们根据创建的mem_map,调用SpaceBitmap构造函数,初始化

    //----bitmap_begin      SpaceBitmap内存基地址

    //----bitmap_size         SpaceBitmap的内存大小

    //----heap_begin          标记的heap的内存基地址

    //----heap_capacity      标记的heap的大小

    return new SpaceBitmap(name, std::move(mem_map), bitmap_begin, bitmap_size, heap_begin, heap_capacity);

}

 

  

b.标记函数set  和清除函数 ,传入对象的地址

bool Set(const mirror::Object* obj) ALWAYS_INLINE {

    return Modify<true>(obj);

}  

bool Clear(const mirror::Object* obj) ALWAYS_INLINE {

    return Modify<false>(obj);

}

template<size_t kAlignment>

template<bool kSetBit>

inline bool SpaceBitmap<kAlignment>::Modify(const mirror::Object* obj) {

    //将obj的地址转换为uintptr_t 对象

    uintptr_t addr = reinterpret_cast<uintptr_t>(obj);

    //计算obj相对于heap基地址的偏移

    const uintptr_t offset = addr - heap_begin_;

    //根据偏移大小计算标记位在spaceBitmap中uintptr_t 对象的位置

    const size_t index = OffsetToIndex(offset);

    //根据偏移大小计算标记bit位在uintptr_t 对象中的位置,也就是mask 对象中对应的bit位为1,其他bit位为0

    const uintptr_t mask = OffsetToMask(offset);

    //根据index 取出对应标记uintptr_t对象atomic_entry

    Atomic<uintptr_t>* atomic_entry = &bitmap_begin_[index];

    //读出atomic_entry 的值

    uintptr_t old_word = atomic_entry->load(std::memory_order_relaxed);

    if (kSetBit) {//set是true,clear是false

        if ((old_word & mask) == 0) {//没有被标记这个判断为0,则进行标记

            atomic_entry->store(old_word | mask, std::memory_order_relaxed);

        }

    else {

        清除标记,对应位置1=0

        atomic_entry->store(old_word & ~mask, std::memory_order_relaxed);

    }

    return (old_word & mask) != 0;

}

 

 

c.遍历函数Walk

template<size_t kAlignment>

template<typename Visitor>

void SpaceBitmap<kAlignment>::Walk(Visitor&& visitor) {

    //计算目前使用的heap对应的bitmap大小

    uintptr_t end = OffsetToIndex(HeapLimit() - heap_begin_ - 1);

           

    Atomic<uintptr_t>* bitmap_begin = bitmap_begin_;

    //遍历bitmap的uintptr_t 对象

    for (uintptr_t i = 0; i <= end; ++i) {

        //取出uintptr_t 值

        uintptr_t w = bitmap_begin[i].load(std::memory_order_relaxed);

        if (w != 0) {//对应的uintptr_t 有bit位为1,也就是有对应的标记对象

            uintptr_t ptr_base = IndexToOffset(i) + heap_begin_;//找到uintptr_t 标记对象的偏移地址,然后+base得到实际地址

            do {

                //找到uintptr_t 不为0的第一个位置,低位开始

                const size_t shift = CTZ(w);

                //拿到shift 标记的内存的地址,并转化为object对象

                mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment);

                //回调visitor函数

                visitor(obj);

                w ^= (static_cast<uintptr_t>(1)) << shift;//把对应位置0,好继续找下一个非0位

            while (w != 0);

        }

    }

}


HeapBitMap

它是一个辅助类,里面存了两个重要的对象

// Bitmaps covering continuous spaces.
std::vector<ContinuousSpaceBitmap*,TrackingAllocator<ContinuousSpaceBitmap*, kAllocatorTagHeapBitmap>>continuous_space_bitmaps_;

// Sets covering discontinuous spaces.
std::vector<LargeObjectBitmap*,TrackingAllocator<LargeObjectBitmap*, kAllocatorTagHeapBitmapLOS>>large_object_bitmaps_;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis 的 Bitmap 类型是一种特殊的字符串类型,它可以用来处理一些基于二进制位的数据结构,例如布隆过滤器(Bloom Filter)或者统计用户在线时长等。 Bitmap 类型支持的操作包括: - bitset key offset value:将指定偏移量上的二进制位设置为 1 或 0。 - bitget key offset:获取指定偏移量上的二进制位的值。 - bitcount key [start end]:计算指定范围内的二进制位被设置为 1 的个数。 - bitop operation destkey key [key ...]:对多个 Bitmap 进行按位操作,并将结果保存到目标 Bitmap 中。 - bitpos key bit [start] [end]:在指定范围内查找第一个被设置为指定值的二进制位的位置。 以下是一个示例,演示如何使用 Bitmap 类型来统计用户在线时长: ``` # 将用户的登录时间记录到 Bitmap 中 # 假设用户 ID 为 1001,登录时间为 2021-10-01 10:00:00,登录时长为 30 分钟 # 将 2021-10-01 10:00:00 转换为时间戳,并除以 300,得到登录时间所在的 5 分钟时间段 redis> setbit online:1001 200 1 # 查询用户在线时长 # 统计 2021-10-01 10:00:00 ~ 2021-10-01 10:30:00 时间段内,用户在线的 5 分钟时间段个数 redis> bitcount online:1001 0 -1 6 ``` 在上面的示例中,我们将用户的登录时间记录到 online:1001 这个 Bitmap 中,偏移量为 200 的二进制位被设置为 1。接着,我们使用 bitcount 命令来统计该 Bitmap 中被设置为 1 的二进制位数量,即用户在线的时间段个数。由于每个时间段为 5 分钟,因此在线时长为 30 分钟,对应的时间段个数为 6。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值