// 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 #include #if USE_JEMALLOC #include #else #include #include #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(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(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(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(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(size)); } else { // Innaccurate because malloc_usable_size() result is greater or equal to allocated size. memgraph::utils::total_memory_tracker.Free(static_cast(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(size)); } else { // Innaccurate because malloc_usable_size() result is greater or equal to allocated size. memgraph::utils::total_memory_tracker.Free(static_cast(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); }