Files
memgraph/src/memory/new_delete.cpp
Antonio Filipovic 7f7f3adfcb Implement jemalloc extent hooks memory tracker (#1250)
Should improve/fix memory usage exceeds --memory-limit issues
2023-10-23 12:48:26 +02:00

258 lines
6.7 KiB
C++

// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include <cstddef>
#include <new>
#if USE_JEMALLOC
#include <jemalloc/jemalloc.h>
#else
#include <malloc.h>
#include <cstdlib>
#endif
#include "utils/memory_tracker.hpp"
namespace {
void *newImpl(const std::size_t size) {
auto *ptr = malloc(size);
if (ptr != nullptr) [[likely]] {
return ptr;
}
throw std::bad_alloc{};
}
void *newImpl(const std::size_t size, const std::align_val_t align) {
auto *ptr = aligned_alloc(static_cast<std::size_t>(align), size);
if (ptr != nullptr) [[likely]] {
return ptr;
}
throw std::bad_alloc{};
}
void *newNoExcept(const std::size_t size) noexcept { return malloc(size); }
void *newNoExcept(const std::size_t size, const std::align_val_t align) noexcept {
return aligned_alloc(size, static_cast<std::size_t>(align));
}
#if USE_JEMALLOC
void deleteImpl(void *ptr) noexcept {
if (ptr == nullptr) [[unlikely]] {
return;
}
dallocx(ptr, 0);
}
void deleteImpl(void *ptr, const std::align_val_t align) noexcept {
if (ptr == nullptr) [[unlikely]] {
return;
}
dallocx(ptr, MALLOCX_ALIGN(align)); // NOLINT(hicpp-signed-bitwise)
}
void deleteSized(void *ptr, const std::size_t size) noexcept {
if (ptr == nullptr) [[unlikely]] {
return;
}
sdallocx(ptr, size, 0);
}
void deleteSized(void *ptr, const std::size_t size, const std::align_val_t align) noexcept {
if (ptr == nullptr) [[unlikely]] {
return;
}
sdallocx(ptr, size, MALLOCX_ALIGN(align)); // NOLINT(hicpp-signed-bitwise)
}
#else
void deleteImpl(void *ptr) noexcept { free(ptr); }
void deleteImpl(void *ptr, const std::align_val_t /*unused*/) noexcept { free(ptr); }
void deleteSized(void *ptr, const std::size_t /*unused*/) noexcept { free(ptr); }
void deleteSized(void *ptr, const std::size_t /*unused*/, const std::align_val_t /*unused*/) noexcept { free(ptr); }
#endif
void TrackMemory(std::size_t size) {
#if !USE_JEMALLOC
memgraph::utils::total_memory_tracker.Alloc(static_cast<int64_t>(size));
#endif
}
void TrackMemory(std::size_t size, const std::align_val_t align) {
#if !USE_JEMALLOC
memgraph::utils::total_memory_tracker.Alloc(static_cast<int64_t>(size));
#endif
}
bool TrackMemoryNoExcept(const std::size_t size) {
try {
TrackMemory(size);
} catch (...) {
return false;
}
return true;
}
bool TrackMemoryNoExcept(const std::size_t size, const std::align_val_t align) {
try {
TrackMemory(size, align);
} catch (...) {
return false;
}
return true;
}
void UntrackMemory([[maybe_unused]] void *ptr, [[maybe_unused]] std::size_t size = 0) noexcept {
try {
#if !USE_JEMALLOC
if (size) {
memgraph::utils::total_memory_tracker.Free(static_cast<int64_t>(size));
} else {
// Innaccurate because malloc_usable_size() result is greater or equal to allocated size.
memgraph::utils::total_memory_tracker.Free(static_cast<int64_t>(malloc_usable_size(ptr)));
}
#endif
} catch (...) {
}
}
void UntrackMemory(void *ptr, const std::align_val_t align, [[maybe_unused]] std::size_t size = 0) noexcept {
try {
#if !USE_JEMALLOC
if (size) {
memgraph::utils::total_memory_tracker.Free(static_cast<int64_t>(size));
} else {
// Innaccurate because malloc_usable_size() result is greater or equal to allocated size.
memgraph::utils::total_memory_tracker.Free(static_cast<int64_t>(malloc_usable_size(ptr)));
}
#endif
} catch (...) {
}
}
} // namespace
void *operator new(const std::size_t size) {
TrackMemory(size);
return newImpl(size);
}
void *operator new[](const std::size_t size) {
TrackMemory(size);
return newImpl(size);
}
void *operator new(const std::size_t size, const std::align_val_t align) {
TrackMemory(size, align);
return newImpl(size, align);
}
void *operator new[](const std::size_t size, const std::align_val_t align) {
TrackMemory(size, align);
return newImpl(size, align);
}
void *operator new(const std::size_t size, const std::nothrow_t & /*unused*/) noexcept {
if (TrackMemoryNoExcept(size)) [[likely]] {
return newNoExcept(size);
}
return nullptr;
}
void *operator new[](const std::size_t size, const std::nothrow_t & /*unused*/) noexcept {
if (TrackMemoryNoExcept(size)) [[likely]] {
return newNoExcept(size);
}
return nullptr;
}
void *operator new(const std::size_t size, const std::align_val_t align, const std::nothrow_t & /*unused*/) noexcept {
if (TrackMemoryNoExcept(size, align)) [[likely]] {
return newNoExcept(size, align);
}
return nullptr;
}
void *operator new[](const std::size_t size, const std::align_val_t align, const std::nothrow_t & /*unused*/) noexcept {
if (TrackMemoryNoExcept(size, align)) [[likely]] {
return newNoExcept(size, align);
}
return nullptr;
}
void operator delete(void *ptr) noexcept {
UntrackMemory(ptr);
deleteImpl(ptr);
}
void operator delete[](void *ptr) noexcept {
UntrackMemory(ptr);
deleteImpl(ptr);
}
void operator delete(void *ptr, const std::align_val_t align) noexcept {
UntrackMemory(ptr, align);
deleteImpl(ptr, align);
}
void operator delete[](void *ptr, const std::align_val_t align) noexcept {
UntrackMemory(ptr, align);
deleteImpl(ptr, align);
}
void operator delete(void *ptr, const std::size_t size) noexcept {
UntrackMemory(ptr, size);
deleteSized(ptr, size);
}
void operator delete[](void *ptr, const std::size_t size) noexcept {
UntrackMemory(ptr, size);
deleteSized(ptr, size);
}
void operator delete(void *ptr, const std::size_t size, const std::align_val_t align) noexcept {
UntrackMemory(ptr, align, size);
deleteSized(ptr, size, align);
}
void operator delete[](void *ptr, const std::size_t size, const std::align_val_t align) noexcept {
UntrackMemory(ptr, align, size);
deleteSized(ptr, size, align);
}
void operator delete(void *ptr, const std::nothrow_t & /*unused*/) noexcept {
UntrackMemory(ptr);
deleteImpl(ptr);
}
void operator delete[](void *ptr, const std::nothrow_t & /*unused*/) noexcept {
UntrackMemory(ptr);
deleteImpl(ptr);
}
void operator delete(void *ptr, const std::align_val_t align, const std::nothrow_t & /*unused*/) noexcept {
UntrackMemory(ptr, align);
deleteImpl(ptr, align);
}
void operator delete[](void *ptr, const std::align_val_t align, const std::nothrow_t & /*unused*/) noexcept {
UntrackMemory(ptr, align);
deleteImpl(ptr, align);
}