diff options
-rw-r--r-- | third_party/tcmalloc/chromium/src/heap-profile-table.cc | 57 | ||||
-rw-r--r-- | third_party/tcmalloc/chromium/src/heap-profile-table.h | 8 | ||||
-rw-r--r-- | third_party/tcmalloc/chromium/src/heap-profiler.cc | 47 |
3 files changed, 79 insertions, 33 deletions
diff --git a/third_party/tcmalloc/chromium/src/heap-profile-table.cc b/third_party/tcmalloc/chromium/src/heap-profile-table.cc index 1ef1858..696f41e 100644 --- a/third_party/tcmalloc/chromium/src/heap-profile-table.cc +++ b/third_party/tcmalloc/chromium/src/heap-profile-table.cc @@ -123,7 +123,12 @@ static bool ByAllocatedSpace(HeapProfileTable::Stats* a, //---------------------------------------------------------------------- HeapProfileTable::HeapProfileTable(Allocator alloc, DeAllocator dealloc) - : alloc_(alloc), dealloc_(dealloc) { + : alloc_(alloc), + dealloc_(dealloc), + num_alloc_buckets_(0), + mmap_table_(NULL), + num_available_mmap_buckets_(0), + mmap_address_map_(NULL) { // Initialize the overall profile stats. memset(&total_, 0, sizeof(total_)); @@ -131,16 +136,10 @@ HeapProfileTable::HeapProfileTable(Allocator alloc, DeAllocator dealloc) const int alloc_table_bytes = kHashTableSize * sizeof(*alloc_table_); alloc_table_ = reinterpret_cast<Bucket**>(alloc_(alloc_table_bytes)); memset(alloc_table_, 0, alloc_table_bytes); - num_alloc_buckets_ = 0; - - // Initialize the mmap table. - mmap_table_ = NULL; - num_available_mmap_buckets_ = 0; // Make malloc and mmap allocation maps. alloc_address_map_ = new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_); - mmap_address_map_ = NULL; } HeapProfileTable::~HeapProfileTable() { @@ -355,7 +354,8 @@ HeapProfileTable::MakeSortedBucketList() const { return list; } -void HeapProfileTable::RefreshMMapData() { +void HeapProfileTable::RefreshMMapData(Allocator mmap_alloc, + DeAllocator mmap_dealloc) { // Make the table static const int mmap_table_bytes = kHashTableSize * sizeof(*mmap_table_); if (mmap_table_ == NULL) { @@ -365,8 +365,8 @@ void HeapProfileTable::RefreshMMapData() { num_available_mmap_buckets_ = 0; ClearMMapData(); - mmap_address_map_ = - new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_); + mmap_address_map_ = new(alloc_(sizeof(AllocationMap))) + AllocationMap(mmap_alloc, mmap_dealloc); MemoryRegionMap::LockHolder l; for (MemoryRegionMap::RegionIterator r = @@ -388,12 +388,12 @@ void HeapProfileTable::RefreshMMapData() { } void HeapProfileTable::ClearMMapData() { - if (mmap_address_map_ != NULL) { - mmap_address_map_->Iterate(ZeroBucketCountsIterator, this); - mmap_address_map_->~AllocationMap(); - dealloc_(mmap_address_map_); - mmap_address_map_ = NULL; - } + if (mmap_address_map_ == NULL) return; + + mmap_address_map_->Iterate(ZeroBucketCountsIterator, this); + mmap_address_map_->~AllocationMap(); + dealloc_(mmap_address_map_); + mmap_address_map_ = NULL; } void HeapProfileTable::IterateOrderedAllocContexts( @@ -505,22 +505,21 @@ bool HeapProfileTable::WriteProfile(const char* file_name, AllocationMap* allocations) { RAW_VLOG(1, "Dumping non-live heap profile to %s", file_name); RawFD fd = RawOpenForWriting(file_name); - if (fd != kIllegalRawFD) { - RawWrite(fd, kProfileHeader, strlen(kProfileHeader)); - char buf[512]; - int len = UnparseBucket(total, buf, 0, sizeof(buf), " heapprofile", - NULL); - RawWrite(fd, buf, len); - const DumpArgs args(fd, NULL); - allocations->Iterate<const DumpArgs&>(DumpNonLiveIterator, args); - RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader)); - DumpProcSelfMaps(fd); - RawClose(fd); - return true; - } else { + if (fd == kIllegalRawFD) { RAW_LOG(ERROR, "Failed dumping filtered heap profile to %s", file_name); return false; } + RawWrite(fd, kProfileHeader, strlen(kProfileHeader)); + char buf[512]; + int len = UnparseBucket(total, buf, 0, sizeof(buf), " heapprofile", + NULL); + RawWrite(fd, buf, len); + const DumpArgs args(fd, NULL); + allocations->Iterate<const DumpArgs&>(DumpNonLiveIterator, args); + RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader)); + DumpProcSelfMaps(fd); + RawClose(fd); + return true; } void HeapProfileTable::CleanupOldProfiles(const char* prefix) { diff --git a/third_party/tcmalloc/chromium/src/heap-profile-table.h b/third_party/tcmalloc/chromium/src/heap-profile-table.h index 447943d..61493fc 100644 --- a/third_party/tcmalloc/chromium/src/heap-profile-table.h +++ b/third_party/tcmalloc/chromium/src/heap-profile-table.h @@ -190,7 +190,13 @@ class HeapProfileTable { // Refresh the internal mmap information from MemoryRegionMap. Results of // FillOrderedProfile and IterateOrderedAllocContexts will contain mmap'ed // memory regions as at calling RefreshMMapData. - void RefreshMMapData(); + // 'mmap_alloc' is an allocator for an address map. A function which calls + // LowLevelAlloc::AllocWithArena is expected like the constractor. + // 'mmap_dealloc' is a corresponding deallocator to 'mmap_alloc'. + // They are introduced to avoid expected memory fragmentation and bloat in + // an arena. A dedicated arena for this function allows disposing whole the + // arena after ClearMMapData. + void RefreshMMapData(Allocator mmap_alloc, DeAllocator mmap_dealloc); // Clear the internal mmap information. Results of FillOrderedProfile and // IterateOrderedAllocContexts won't contain mmap'ed memory regions after diff --git a/third_party/tcmalloc/chromium/src/heap-profiler.cc b/third_party/tcmalloc/chromium/src/heap-profiler.cc index 85d1aad..73f31f7 100644 --- a/third_party/tcmalloc/chromium/src/heap-profiler.cc +++ b/third_party/tcmalloc/chromium/src/heap-profiler.cc @@ -143,7 +143,7 @@ static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED); // Simple allocator for heap profiler's internal memory //---------------------------------------------------------------------- -static LowLevelAlloc::Arena *heap_profiler_memory; +static LowLevelAlloc::Arena* heap_profiler_memory; static void* ProfilerMalloc(size_t bytes) { return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory); @@ -152,6 +152,36 @@ static void ProfilerFree(void* p) { LowLevelAlloc::Free(p); } +//---------------------------------------------------------------------- +// Another allocator for heap profiler's internal mmap address map +// +// Large amount of memory is consumed if we use an arena 'heap_profiler_memory' +// for the internal mmap address map. It looks like memory fragmentation +// because of repeated allocation/deallocation in the arena. +// +// 'mmap_heap_profiler_memory' is a dedicated arena for the mmap address map. +// This arena is reserved for every construction of the mmap address map, and +// disposed after every use. +//---------------------------------------------------------------------- + +static LowLevelAlloc::Arena* mmap_heap_profiler_memory = NULL; + +static void* MMapProfilerMalloc(size_t bytes) { + return LowLevelAlloc::AllocWithArena(bytes, mmap_heap_profiler_memory); +} +static void MMapProfilerFree(void* p) { + LowLevelAlloc::Free(p); +} + +// This function should be called from a locked scope. +// It returns false if failed in deleting the arena. +static bool DeleteMMapProfilerArenaIfExistsLocked() { + if (mmap_heap_profiler_memory == NULL) return true; + if (!LowLevelAlloc::DeleteArena(mmap_heap_profiler_memory)) return false; + mmap_heap_profiler_memory = NULL; + return true; +} + // We use buffers of this size in DoGetHeapProfile. // The size is 1 << 20 in the original google-perftools. Changed it to // 5 << 20 since a larger buffer is requried for deeper profiling in Chromium. @@ -200,7 +230,12 @@ static char* DoGetHeapProfileLocked(char* buf, int buflen) { int bytes_written = 0; if (is_on) { if (FLAGS_mmap_profile) { - heap_profile->RefreshMMapData(); + if (!DeleteMMapProfilerArenaIfExistsLocked()) { + RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); + } + mmap_heap_profiler_memory = + LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); + heap_profile->RefreshMMapData(MMapProfilerMalloc, MMapProfilerFree); } if (deep_profile) { bytes_written = deep_profile->FillOrderedProfile(buf, buflen - 1); @@ -209,6 +244,9 @@ static char* DoGetHeapProfileLocked(char* buf, int buflen) { } if (FLAGS_mmap_profile) { heap_profile->ClearMMapData(); + if (!DeleteMMapProfilerArenaIfExistsLocked()) { + RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); + } } } buf[bytes_written] = '\0'; @@ -532,6 +570,9 @@ extern "C" void HeapProfilerStop() { // free profile heap_profile->~HeapProfileTable(); + if (!DeleteMMapProfilerArenaIfExistsLocked()) { + RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); + } ProfilerFree(heap_profile); heap_profile = NULL; @@ -553,7 +594,7 @@ extern "C" void HeapProfilerStop() { is_on = false; } -extern "C" void HeapProfilerDump(const char *reason) { +extern "C" void HeapProfilerDump(const char* reason) { SpinLockHolder l(&heap_lock); if (is_on && !dumping) { DumpProfileLocked(reason); |