mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
utils: dump memory info on crash (#708)
For diagnosing out of memory errors / malloc failures.
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/libutils.h"
|
#include "util/libutils.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
|
#include "util/memutils.h"
|
||||||
#include "cfg/configurator.h"
|
#include "cfg/configurator.h"
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
@@ -175,6 +176,9 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
|
|||||||
log_warning("signal", "minidump creation function not available, skipping");
|
log_warning("signal", "minidump creation function not available, skipping");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dump memory information
|
||||||
|
memutils::show_available_memory();
|
||||||
|
|
||||||
// this will stall all UI threads for this process
|
// this will stall all UI threads for this process
|
||||||
show_popup_for_crash();
|
show_popup_for_crash();
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,61 @@ namespace memutils {
|
|||||||
return get_mem_counters().PrivateUsage;
|
return get_mem_counters().PrivateUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void show_available_memory() {
|
||||||
|
constexpr double MB = 1024.0 * 1024.0;
|
||||||
|
|
||||||
|
auto mem_status = get_mem_status();
|
||||||
|
|
||||||
|
const auto pct = [](DWORDLONG used, DWORDLONG total) -> double {
|
||||||
|
return total ? (100.0 * static_cast<double>(used) / static_cast<double>(total)) : 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
log_info("memutils",
|
||||||
|
"system physical memory: {:.1f} / {:.1f} MiB used ({:.1f}%)",
|
||||||
|
mem_total_used() / MB, mem_total() / MB,
|
||||||
|
pct(mem_total_used(), mem_total()));
|
||||||
|
|
||||||
|
log_info("memutils",
|
||||||
|
"system page file: {:.1f} / {:.1f} MiB used ({:.1f}%, {:.1f} MiB commit headroom)",
|
||||||
|
vmem_total_used() / MB, vmem_total() / MB,
|
||||||
|
pct(vmem_total_used(), vmem_total()),
|
||||||
|
mem_status.ullAvailPageFile / MB);
|
||||||
|
|
||||||
|
// process virtual address space - 32-bit processes die at ~2 GiB
|
||||||
|
// (or ~4 GiB with /LARGEADDRESSAWARE) regardless of how much RAM is free
|
||||||
|
const DWORDLONG va_used = mem_status.ullTotalVirtual - mem_status.ullAvailVirtual;
|
||||||
|
log_info("memutils",
|
||||||
|
"process virtual address space: {:.1f} / {:.1f} MiB used ({:.1f}%)",
|
||||||
|
va_used / MB, mem_status.ullTotalVirtual / MB,
|
||||||
|
pct(va_used, mem_status.ullTotalVirtual));
|
||||||
|
|
||||||
|
// largest contiguous free block in the process address space
|
||||||
|
// (large allocations can fail due to fragmentation even with plenty available)
|
||||||
|
MEMORY_BASIC_INFORMATION mbi{};
|
||||||
|
SIZE_T largest_free = 0;
|
||||||
|
uintptr_t addr = 0;
|
||||||
|
const uintptr_t max_addr = static_cast<uintptr_t>(mem_status.ullTotalVirtual);
|
||||||
|
while (addr < max_addr &&
|
||||||
|
VirtualQuery(reinterpret_cast<LPCVOID>(addr), &mbi, sizeof(mbi)) == sizeof(mbi)) {
|
||||||
|
if (mbi.State == MEM_FREE && mbi.RegionSize > largest_free) {
|
||||||
|
largest_free = mbi.RegionSize;
|
||||||
|
}
|
||||||
|
const uintptr_t next = reinterpret_cast<uintptr_t>(mbi.BaseAddress) + mbi.RegionSize;
|
||||||
|
if (next <= addr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
addr = next;
|
||||||
|
}
|
||||||
|
log_info("memutils",
|
||||||
|
"process largest free virtual block: {:.1f} MiB ({:.1f}% of total VA)",
|
||||||
|
largest_free / MB,
|
||||||
|
pct(largest_free, mem_status.ullTotalVirtual));
|
||||||
|
|
||||||
|
log_info("memutils",
|
||||||
|
"process working set: {:.1f} MiB, private bytes: {:.1f} MiB",
|
||||||
|
mem_used() / MB, vmem_used() / MB);
|
||||||
|
}
|
||||||
|
|
||||||
VProtectGuard::VProtectGuard(void *addr, size_t size, DWORD mode, bool reset)
|
VProtectGuard::VProtectGuard(void *addr, size_t size, DWORD mode, bool reset)
|
||||||
: addr(addr), reset(reset), size(size)
|
: addr(addr), reset(reset), size(size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace memutils {
|
|||||||
DWORDLONG vmem_total_used();
|
DWORDLONG vmem_total_used();
|
||||||
DWORDLONG vmem_used();
|
DWORDLONG vmem_used();
|
||||||
|
|
||||||
|
void show_available_memory();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper class to unprotect/reprotect memory safely.
|
* Helper class to unprotect/reprotect memory safely.
|
||||||
* It will free it's mode override on destruction.
|
* It will free it's mode override on destruction.
|
||||||
|
|||||||
Reference in New Issue
Block a user