Real Kernel RSS & File Descriptor Tracking
Standard PHP functions like memory_get_usage() and memory_get_peak_usage() only measure memory allocated inside the Zend Engine heap (the internal memory manager for PHP objects, arrays, and variables).
They are completely blind to:
- C-extensions (
curl,imagick,gd,openssl,ext-sodium) - Native glibc
malloc()/jemalloc/mimallocallocations - Unclosed File Descriptors (
/proc/self/fd) and lingering sockets
1. The Linux /proc/self/statm Interface
On Linux, the kernel maintains an ultra-fast pseudo-filesystem file for every process: /proc/self/statm.
Reading this file does not trigger disk I/O; the kernel directly exposes the process memory page table:
20480 12800 3840 256 0 10240 0Where the values represent:
- Total Program Size (Size): Total virtual memory size (in pages).
- Resident Set Size (RSS): Real physical RAM currently occupied by the process (in pages).
- Shared Pages (Shared): Pages mapped to shared libraries.
- Text / Code (Text): Executable code segment.
- Library (Lib): Shared library pages.
- Data + Stack (Data): Process data segment and user stack.
- Dirty Pages (Dirty): Modified physical memory pages.
How Leakless Computes RSS
- Kernel Page Resolution: Dynamically resolves the Linux page size via POSIX
posix_sysconf(POSIX_PC_SC_PAGESIZE)(typically4096bytes). - Zero-Allocation Parsing:
ProcStatmParserreads/proc/self/statmat request boundaries. - Megabyte Conversion: Converts page counts directly to megabytes: $$\text{RSS (MB)} = \frac{\text{resident_pages} \times \text{page_size_bytes}}{1024 \times 1024}$$
2. File Descriptor Guard (/proc/self/fd)
In persistent PHP workers, unclosed file handles (fopen()), temporary streams, or open network sockets (fsockopen(), cURL handles) accumulate in the process table.
Over time, this breaches the operating system limit (ulimit -n), causing fatal errors: Too many open files
How FileDescriptorGuard Operates
When checkFileDescriptors: true (or LEAKLESS_CHECK_FILE_DESCRIPTORS=true):
- Initial Snapshot: Reads
/proc/self/fdsymlinks atstartRequest(). - Post-Request Audit: Re-inspects
/proc/self/fdatendRequest(). - Leak Identification: Detects descriptors opened during request processing that were left unclosed.
- Diagnostic Logging: Emits detailed warnings with file paths and sets
$report->fileDescriptorsLeaked = true.