24#include <sys/resource.h>
27#define Q3_HAS_MALLOC_TRIM 1
28#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 33)
29#define Q3_HAS_MALLINFO2 1
32#elif defined(__APPLE__)
34#include <malloc/malloc.h>
35#include <sys/resource.h>
64 return static_cast<double>(bytes) / 1073741824.0;
78 ResidentMemorySample result;
79 std::FILE* status_file = std::fopen(
"/proc/self/status",
"r");
80 if (status_file !=
nullptr) {
82 while (std::fgets(line,
sizeof(line), status_file) !=
nullptr) {
83 unsigned long long kilobytes = 0;
84 if (std::sscanf(line,
"VmRSS: %llu kB", &kilobytes) == 1) {
85 result.current_bytes =
static_cast<std::uint64_t
>(kilobytes) * 1024;
86 result.available =
true;
87 }
else if (std::sscanf(line,
"VmHWM: %llu kB", &kilobytes) == 1) {
88 result.peak_bytes =
static_cast<std::uint64_t
>(kilobytes) * 1024;
89 result.available =
true;
90 }
else if (std::sscanf(line,
"RssAnon: %llu kB", &kilobytes) == 1) {
91 result.anonymous_bytes =
static_cast<std::uint64_t
>(kilobytes) * 1024;
92 }
else if (std::sscanf(line,
"RssShmem: %llu kB", &kilobytes) == 1) {
93 result.shared_bytes =
static_cast<std::uint64_t
>(kilobytes) * 1024;
96 std::fclose(status_file);
98 if (result.peak_bytes == 0) {
100 if (getrusage(RUSAGE_SELF, &usage) == 0) {
101 result.peak_bytes =
static_cast<std::uint64_t
>(usage.ru_maxrss) * 1024;
102 result.available =
true;
105#if defined(Q3_HAS_MALLINFO2)
106 struct mallinfo2 allocator_info = mallinfo2();
107 result.malloc_in_use_bytes =
static_cast<std::uint64_t
>(allocator_info.uordblks) +
108 static_cast<std::uint64_t
>(allocator_info.hblkhd);
113#elif defined(__APPLE__)
121 ResidentMemorySample result;
122 mach_task_basic_info task_information;
123 mach_msg_type_number_t information_count = MACH_TASK_BASIC_INFO_COUNT;
124 if (task_info(mach_task_self(),
125 MACH_TASK_BASIC_INFO,
126 reinterpret_cast<task_info_t
>(&task_information),
127 &information_count) == KERN_SUCCESS) {
128 result.
current_bytes =
static_cast<std::uint64_t
>(task_information.resident_size);
129 result.peak_bytes =
static_cast<std::uint64_t
>(task_information.resident_size_max);
130 result.available =
true;
133 if (getrusage(RUSAGE_SELF, &usage) == 0) {
134 std::uint64_t reported_peak =
static_cast<std::uint64_t
>(usage.ru_maxrss);
135 if (reported_peak > result.peak_bytes) {
136 result.peak_bytes = reported_peak;
138 result.available =
true;
154 std::snprintf(buffer,
sizeof(buffer),
"%.2f GiB",
to_gibibytes(bytes));
155 return std::string(buffer);
175#if defined(Q3_HAS_MALLOC_TRIM)
178#elif defined(__APPLE__)
179 return static_cast<std::uint64_t
>(malloc_zone_pressure_relief(
nullptr, 0));
std::uint64_t release_unused_heap()
std::uint64_t anonymous_bytes
Resident anonymous pages: heap and stack, what this process allocated.
static ResidentMemorySample sample()
Platforms without a known source report nothing rather than guessing.
static double to_gibibytes(std::uint64_t bytes)
static std::string format_gibibytes(std::uint64_t bytes)
std::uint64_t malloc_in_use_bytes
Bytes the C allocator reports as handed out, where it can be asked.
std::uint64_t shared_bytes
Resident shared pages: mapped files and shared-memory segments.
std::uint64_t current_bytes
Resident set size at the moment of sampling.
std::uint64_t peak_bytes
High-water mark of the resident set over the life of the process.
bool available
Whether any source could be read.