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%
  • 數字越大越好,非線性反比關系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM