memory_reclaimer.cc 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/allocator/partition_allocator/memory_reclaimer.h"
  5. #include "base/allocator/partition_allocator/partition_alloc.h"
  6. #include "base/allocator/partition_allocator/partition_alloc_base/no_destructor.h"
  7. #include "base/allocator/partition_allocator/partition_alloc_check.h"
  8. #include "base/allocator/partition_allocator/partition_alloc_config.h"
  9. #include "base/allocator/partition_allocator/starscan/pcscan.h"
  10. // TODO(bikineev): Temporarily disable *Scan in MemoryReclaimer as it seems to
  11. // cause significant jank.
  12. #define PA_STARSCAN_ENABLE_STARSCAN_ON_RECLAIM 0
  13. namespace partition_alloc {
  14. // static
  15. MemoryReclaimer* MemoryReclaimer::Instance() {
  16. static internal::base::NoDestructor<MemoryReclaimer> instance;
  17. return instance.get();
  18. }
  19. void MemoryReclaimer::RegisterPartition(PartitionRoot<>* partition) {
  20. internal::ScopedGuard lock(lock_);
  21. PA_DCHECK(partition);
  22. auto it_and_whether_inserted = partitions_.insert(partition);
  23. PA_DCHECK(it_and_whether_inserted.second);
  24. }
  25. void MemoryReclaimer::UnregisterPartition(
  26. PartitionRoot<internal::ThreadSafe>* partition) {
  27. internal::ScopedGuard lock(lock_);
  28. PA_DCHECK(partition);
  29. size_t erased_count = partitions_.erase(partition);
  30. PA_DCHECK(erased_count == 1u);
  31. }
  32. MemoryReclaimer::MemoryReclaimer() = default;
  33. MemoryReclaimer::~MemoryReclaimer() = default;
  34. void MemoryReclaimer::ReclaimAll() {
  35. constexpr int kFlags = PurgeFlags::kDecommitEmptySlotSpans |
  36. PurgeFlags::kDiscardUnusedSystemPages |
  37. PurgeFlags::kAggressiveReclaim;
  38. Reclaim(kFlags);
  39. }
  40. void MemoryReclaimer::ReclaimNormal() {
  41. constexpr int kFlags = PurgeFlags::kDecommitEmptySlotSpans |
  42. PurgeFlags::kDiscardUnusedSystemPages;
  43. Reclaim(kFlags);
  44. }
  45. void MemoryReclaimer::Reclaim(int flags) {
  46. internal::ScopedGuard lock(
  47. lock_); // Has to protect from concurrent (Un)Register calls.
  48. // PCScan quarantines freed slots. Trigger the scan first to let it call
  49. // FreeNoHooksImmediate on slots that pass the quarantine.
  50. //
  51. // In turn, FreeNoHooksImmediate may add slots to thread cache. Purge it next
  52. // so that the slots are actually freed. (This is done synchronously only for
  53. // the current thread.)
  54. //
  55. // Lastly decommit empty slot spans and lastly try to discard unused pages at
  56. // the end of the remaining active slots.
  57. #if PA_STARSCAN_ENABLE_STARSCAN_ON_RECLAIM
  58. {
  59. using PCScan = internal::PCScan;
  60. const auto invocation_mode = flags & PurgeFlags::kAggressiveReclaim
  61. ? PCScan::InvocationMode::kForcedBlocking
  62. : PCScan::InvocationMode::kBlocking;
  63. PCScan::PerformScanIfNeeded(invocation_mode);
  64. }
  65. #endif
  66. #if defined(PA_THREAD_CACHE_SUPPORTED)
  67. // Don't completely empty the thread cache outside of low memory situations,
  68. // as there is periodic purge which makes sure that it doesn't take too much
  69. // space.
  70. if (flags & PurgeFlags::kAggressiveReclaim)
  71. ThreadCacheRegistry::Instance().PurgeAll();
  72. #endif
  73. for (auto* partition : partitions_)
  74. partition->PurgeMemory(flags);
  75. }
  76. void MemoryReclaimer::ResetForTesting() {
  77. internal::ScopedGuard lock(lock_);
  78. partitions_.clear();
  79. }
  80. } // namespace partition_alloc