2019-07-19 12:57:23 +00:00
|
|
|
#include <common/config_common.h>
|
2019-07-11 15:40:55 +00:00
|
|
|
#include <common/memory.h>
|
2019-07-10 18:12:50 +00:00
|
|
|
#include <Common/MemoryTracker.h>
|
|
|
|
|
2020-01-16 12:37:29 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <new>
|
|
|
|
|
|
|
|
#if defined(OS_LINUX)
|
|
|
|
# include <malloc.h>
|
|
|
|
#elif defined(OS_DARWIN)
|
|
|
|
# include <malloc/malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2019-07-10 18:12:50 +00:00
|
|
|
/// Replace default new/delete with memory tracking versions.
|
|
|
|
/// @sa https://en.cppreference.com/w/cpp/memory/new/operator_new
|
|
|
|
/// https://en.cppreference.com/w/cpp/memory/new/operator_delete
|
2019-07-25 10:35:57 +00:00
|
|
|
#if !UNBUNDLED
|
2019-07-10 18:12:50 +00:00
|
|
|
|
2019-07-15 13:19:56 +00:00
|
|
|
namespace Memory
|
|
|
|
{
|
|
|
|
|
2020-03-19 10:38:34 +00:00
|
|
|
inline ALWAYS_INLINE void trackMemory(std::size_t size)
|
2019-07-15 13:19:56 +00:00
|
|
|
{
|
2019-07-15 18:57:00 +00:00
|
|
|
#if USE_JEMALLOC
|
|
|
|
/// The nallocx() function allocates no memory, but it performs the same size computation as the mallocx() function
|
|
|
|
/// @note je_mallocx() != je_malloc(). It's expected they don't differ much in allocation logic.
|
2019-07-16 16:36:10 +00:00
|
|
|
if (likely(size != 0))
|
|
|
|
CurrentMemoryTracker::alloc(nallocx(size, 0));
|
2019-07-15 13:19:56 +00:00
|
|
|
#else
|
|
|
|
CurrentMemoryTracker::alloc(size);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-03-19 10:38:34 +00:00
|
|
|
inline ALWAYS_INLINE bool trackMemoryNoExcept(std::size_t size) noexcept
|
2019-07-15 13:19:56 +00:00
|
|
|
{
|
2019-07-15 18:57:00 +00:00
|
|
|
try
|
|
|
|
{
|
2019-07-16 16:36:10 +00:00
|
|
|
trackMemory(size);
|
2019-07-15 18:57:00 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2019-07-15 13:19:56 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 10:38:34 +00:00
|
|
|
inline ALWAYS_INLINE void untrackMemory(void * ptr [[maybe_unused]], std::size_t size [[maybe_unused]] = 0) noexcept
|
2019-07-15 13:19:56 +00:00
|
|
|
{
|
2019-07-15 18:57:00 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
#if USE_JEMALLOC
|
|
|
|
/// @note It's also possible to use je_malloc_usable_size() here.
|
|
|
|
if (likely(ptr != nullptr))
|
|
|
|
CurrentMemoryTracker::free(sallocx(ptr, 0));
|
2019-07-15 13:19:56 +00:00
|
|
|
#else
|
2019-07-15 18:57:00 +00:00
|
|
|
if (size)
|
|
|
|
CurrentMemoryTracker::free(size);
|
2020-01-16 12:37:29 +00:00
|
|
|
# ifdef _GNU_SOURCE
|
2019-08-12 12:21:07 +00:00
|
|
|
/// It's innaccurate resource free for sanitizers. malloc_usable_size() result is greater or equal to allocated size.
|
|
|
|
else
|
|
|
|
CurrentMemoryTracker::free(malloc_usable_size(ptr));
|
2020-01-16 12:37:29 +00:00
|
|
|
# endif
|
2019-07-15 13:19:56 +00:00
|
|
|
#endif
|
2019-07-15 18:57:00 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{}
|
2019-07-15 13:19:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-07-11 15:40:55 +00:00
|
|
|
/// new
|
|
|
|
|
|
|
|
void * operator new(std::size_t size)
|
2019-07-10 18:12:50 +00:00
|
|
|
{
|
2019-07-15 18:57:00 +00:00
|
|
|
Memory::trackMemory(size);
|
|
|
|
return Memory::newImpl(size);
|
2019-07-11 15:40:55 +00:00
|
|
|
}
|
2019-07-10 18:12:50 +00:00
|
|
|
|
2019-07-11 15:40:55 +00:00
|
|
|
void * operator new[](std::size_t size)
|
|
|
|
{
|
2019-07-15 18:57:00 +00:00
|
|
|
Memory::trackMemory(size);
|
|
|
|
return Memory::newImpl(size);
|
2019-07-11 15:40:55 +00:00
|
|
|
}
|
2019-07-10 18:12:50 +00:00
|
|
|
|
2019-07-11 15:40:55 +00:00
|
|
|
void * operator new(std::size_t size, const std::nothrow_t &) noexcept
|
|
|
|
{
|
2020-01-16 12:37:29 +00:00
|
|
|
if (likely(Memory::trackMemoryNoExcept(size)))
|
2019-07-15 18:57:00 +00:00
|
|
|
return Memory::newNoExept(size);
|
|
|
|
return nullptr;
|
2019-07-11 15:40:55 +00:00
|
|
|
}
|
2019-07-10 18:12:50 +00:00
|
|
|
|
2019-07-11 15:40:55 +00:00
|
|
|
void * operator new[](std::size_t size, const std::nothrow_t &) noexcept
|
|
|
|
{
|
2020-01-16 12:37:29 +00:00
|
|
|
if (likely(Memory::trackMemoryNoExcept(size)))
|
2019-07-15 18:57:00 +00:00
|
|
|
return Memory::newNoExept(size);
|
|
|
|
return nullptr;
|
2019-07-11 15:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// delete
|
|
|
|
|
2019-07-12 14:41:59 +00:00
|
|
|
/// C++17 std 21.6.2.1 (11)
|
|
|
|
/// If a function without a size parameter is defined, the program should also define the corresponding function with a size parameter.
|
|
|
|
/// If a function with a size parameter is defined, the program shall also define the corresponding version without the size parameter.
|
2019-07-11 15:40:55 +00:00
|
|
|
|
2019-07-12 14:41:59 +00:00
|
|
|
/// cppreference:
|
|
|
|
/// It's unspecified whether size-aware or size-unaware version is called when deleting objects of
|
|
|
|
/// incomplete type and arrays of non-class and trivially-destructible class types.
|
2019-07-11 15:40:55 +00:00
|
|
|
|
2019-07-12 14:41:59 +00:00
|
|
|
void operator delete(void * ptr) noexcept
|
2019-07-11 15:40:55 +00:00
|
|
|
{
|
2019-07-15 13:19:56 +00:00
|
|
|
Memory::untrackMemory(ptr);
|
2019-07-11 15:40:55 +00:00
|
|
|
Memory::deleteImpl(ptr);
|
|
|
|
}
|
|
|
|
|
2019-07-12 14:41:59 +00:00
|
|
|
void operator delete[](void * ptr) noexcept
|
2019-07-11 15:40:55 +00:00
|
|
|
{
|
2019-07-15 13:19:56 +00:00
|
|
|
Memory::untrackMemory(ptr);
|
2019-07-11 15:40:55 +00:00
|
|
|
Memory::deleteImpl(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator delete(void * ptr, std::size_t size) noexcept
|
2019-07-10 18:12:50 +00:00
|
|
|
{
|
2019-07-15 13:19:56 +00:00
|
|
|
Memory::untrackMemory(ptr, size);
|
2019-07-11 15:40:55 +00:00
|
|
|
Memory::deleteSized(ptr, size);
|
|
|
|
}
|
2019-07-10 18:12:50 +00:00
|
|
|
|
2019-07-11 15:40:55 +00:00
|
|
|
void operator delete[](void * ptr, std::size_t size) noexcept
|
|
|
|
{
|
2019-07-15 13:19:56 +00:00
|
|
|
Memory::untrackMemory(ptr, size);
|
2019-07-11 15:40:55 +00:00
|
|
|
Memory::deleteSized(ptr, size);
|
2019-07-10 18:12:50 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 15:40:55 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
/// new
|
|
|
|
|
|
|
|
void * operator new(std::size_t size) { return Memory::newImpl(size); }
|
|
|
|
void * operator new[](std::size_t size) { return Memory::newImpl(size); }
|
|
|
|
|
|
|
|
void * operator new(std::size_t size, const std::nothrow_t &) noexcept { return Memory::newNoExept(size); }
|
|
|
|
void * operator new[](std::size_t size, const std::nothrow_t &) noexcept { return Memory::newNoExept(size); }
|
|
|
|
|
|
|
|
/// delete
|
|
|
|
|
|
|
|
void operator delete(void * ptr) noexcept { Memory::deleteImpl(ptr); }
|
|
|
|
void operator delete[](void * ptr) noexcept { Memory::deleteImpl(ptr); }
|
|
|
|
|
|
|
|
void operator delete(void * ptr, const std::nothrow_t &) noexcept { Memory::deleteImpl(ptr); }
|
|
|
|
void operator delete[](void * ptr, const std::nothrow_t &) noexcept { Memory::deleteImpl(ptr); }
|
|
|
|
|
|
|
|
void operator delete(void * ptr, std::size_t size) noexcept { Memory::deleteSized(ptr, size); }
|
|
|
|
void operator delete[](void * ptr, std::size_t size) noexcept { Memory::deleteSized(ptr, size); }
|
|
|
|
|
2019-07-10 18:12:50 +00:00
|
|
|
#endif
|