Tcmalloc SetMemoryReleaseRate(double) 和 ReleaseFreeMemory()浅析

问题

Tcmalloc 由于使用了精心设计的 cache,进而大大提高了malloc 和 free 的效率,但由之而来的是 cache 大小的难以把控,容易出现 cache 占用过大,进而 OOM 的问题,tcmalloc 提供了两个方案解决这个问题

  • 展现 tcmalloc 维护的内存状态解决

    //virtual void GetStats(char* buffer, int buffer_length);
    MallocExtension::instance()->GetStats(buf, length);
    

解决

1.ReleaseFreeMemory

作用
  • 一次性,全部释放 tcmalloc 的 cache 内存
函数实现
// Same as ReleaseToSystem() but release as much memory as possible.
virtual void ReleaseFreeMemory();
// 实现
void MallocExtension::ReleaseFreeMemory() {
  ReleaseToSystem(static_cast<size_t>(-1));   // SIZE_T_MAX
}
//加锁释放,尽可能多的cache
virtual void ReleaseToSystem(size_t num_bytes) {
  SpinLockHolder h(Static::pageheap_lock());
  if (num_bytes <= extra_bytes_released_) {
    // We released too much on a prior call, so don't release any
    // more this time.
    extra_bytes_released_ = extra_bytes_released_ - num_bytes;
    return;
  }
  num_bytes = num_bytes - extra_bytes_released_;
  // num_bytes might be less than one page.  If we pass zero to
  // ReleaseAtLeastNPages, it won't do anything, so we release a whole
  // page now and let extra_bytes_released_ smooth it out over time.
  Length num_pages = max<Length>(num_bytes >> kPageShift, 1);
  size_t bytes_released = Static::pageheap()->ReleaseAtLeastNPages(
    num_pages) << kPageShift;
  if (bytes_released > num_bytes) {
    extra_bytes_released_ = bytes_released - num_bytes;
  } else {
    // The PageHeap wasn't able to release num_bytes.  Don't try to
    // compensate with a big release next time.  Specifically,
    // ReleaseFreeMemory() calls ReleaseToSystem(LONG_MAX).
    extra_bytes_released_ = 0;
  }
}
劣势
  • 对 page heap 加锁,cache 较大时,占用锁时间较长,可能阻塞较长时间
  • 对 tcmalloc 源码的阅读,会在之后的博客中分享

2.SetMemoryReleaseRate

作用
  • 控制释放 cache 给 OS的速度
函数实现
// Sets the rate at which we release unused memory to the system.
// Zero means we never release memory back to the system.  Increase
// this flag to return memory faster; decrease it to return memory
// slower.  Reasonable rates are in the range [0,10].  (Currently
// only implemented in tcmalloc).
virtual void SetMemoryReleaseRate(double rate);
// 实现
virtual void SetMemoryReleaseRate(double rate) {
  FLAGS_tcmalloc_release_rate = rate;
}
rate的含义
  • 官方建议 [0 , 10]
  • 0 代表不归还,数字越大归还越快,但最大是多少呢?以及是否是线性的呢?
// Incrementally release some memory to the system.
// IncrementalScavenge(n) is called whenever n pages are freed.
// 大意是,释放 n 个 pages 时, 通过 IncrementalScavenge 归还一定大小 cache 给 OS
void IncrementalScavenge(Length n);
// 实现
void PageHeap::IncrementalScavenge(Length n) {
  // Fast path; not yet time to release memory
  // 需要等待的 pages 数,每释放 scavenge_counter_ 个 pages 归还一次给OS
  scavenge_counter_ -= n;
  if (scavenge_counter_ >= 0) return;  // Not yet time to scavenge
  const double rate = FLAGS_tcmalloc_release_rate;
  if (rate <= 1e-6) {
    // 0 不释放
    scavenge_counter_ = kDefaultReleaseDelay;
    return;
  }
  ++stats_.scavenge_count;
  Length released_pages = ReleaseAtLeastNPages(1);
  if (released_pages == 0) {
    scavenge_counter_ = kDefaultReleaseDelay;
  } else {
    // Compute how long to wait until we return memory.
    // FLAGS_tcmalloc_release_rate==1 means wait for 1000 pages
    // after releasing one page.
    // 反比关系,1000 / rate 为要等待的 pages,所以 rate 可以理解为 [1, 1000]
    // 1 时等待1000个pages, 1000时等待1个page
    const double mult = 1000.0 / rate;
    double wait = mult * static_cast<double>(released_pages);
    if (wait > kMaxReleaseDelay) {
      // Avoid overflow and bound to reasonable range.
      wait = kMaxReleaseDelay;
    }
    scavenge_counter_ = static_cast<int64_t>(wait);
  }
}
  • 由此可见,建议在 [0, 1000] 配置
  • 1 时归还率为 1 / 1000, 1000时归还率为 50%
  • 数字越大越好,非线性反比关系
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TCMalloc是一个由Google开发的内存管理器,被广泛用于大规模的分布式系统中。它为多线程环境下的内存分和释放提供了高效的性能。 TCMalloc的实现主要包含以下几个关键特性: 1. Thread-Caching TCMalloc使用了线程本地缓存(Thread-Caching)的机制,每个线程都维护了一个本地缓存,用于快速分配和释放内存。这样可以避免不同线程之间频繁访问共享数据结构的开销,提高了内存分配和释放的性能。 2. Central Cache TCMalloc还维护了一个全局的中央缓存(Central Cache),用于存储较大的内存块。当本地缓存不足以满足内存需求时,线程会向中央缓存申请内存。 3. Page Heap TCMalloc使用了Page Heap来管理内存。Page Heap将内存按页进行划分,并使用位图来跟踪每个页的使用情况。这样可以提高内存分配和释放的效率,并减少内存碎片化。 4. Size Class TCMalloc将需要分配的内存按照大小进行分类,每个大小类都有一个对应的内存池。这样可以提高内存分配和释放的效率,并减少内存碎片化。 5. 高效的内存分配和释放算法 TCMalloc使用了一些高效的算法来管理内存,如位图、堆栈缓存等。这些算法能够快速地分配和释放内存,并且减少内存碎片化。 总的来说,TCMalloc通过使用线程本地缓存、中央缓存、Page Heap以及高效的内存分配和释放算法,实现了高性能的内存管理。它在Google的大规模分布式系统中得到了广泛应用,并取得了很好的效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值