CloudLinux LVE has two memory limits: PMEM (physical memory) and VMEM (virtual memory). Both are documented; both exist in lvectl limits; both can be set per package or per user. But they mean fundamentally different things, and getting them confused leads to either limits that do not bite or limits that bite the wrong way. On modern CloudLinux installs, PMEM is the one that actually matters; VMEM is largely a legacy concept.
What’s happening
VMEM is virtual memory — the total address space a process reserves. This includes memory the process actually uses, memory mapped from files (shared libraries), memory allocated but not touched, and memory in the page cache. A PHP-FPM worker can show 200 MB VMEM while actually using only 40 MB of physical RAM — the rest is mmap’d shared libraries that other workers also reference.
PMEM is physical (resident) memory — the actual RAM the process is consuming. This is what shows up in ps aux RSS column. Multiple PHP-FPM workers sharing the same Composer autoload memory mappings count those bytes once at the host level, but each worker’s PMEM includes them.
The historical rationale for VMEM was protecting against runaway allocations (catch a process that asks for 100 GB even if it only uses 1 GB). Modern Linux on cPanel uses transparent hugepages and aggressive mmap, making VMEM numbers misleadingly large. CloudLinux’s recommendation in recent versions is to set VMEM to 0 (unlimited) and use PMEM as the actual memory cap.
How to verify
Current per-LVE limits and usage:
lvectl limits <username>
lveinfo --user=<username> --period=1h | head
lveinfo --user=<username> --period=24h --show-incidents --by=pmem
lveinfo --user=<username> --period=24h --show-incidents --by=vmem
If you see VMEM incidents with no actual memory pressure on the host (PHP scripts dying with “Out of memory” but free -h shows plenty), VMEM is the limit being hit and it should not be.
Process-level view:
ps -u <username> -o pid,user,rss,vsz,cmd | head -20
rss = resident set (compares to PMEM). vsz = virtual size (compares to VMEM). A worker with 800 MB vsz and 60 MB rss is fine on PMEM but might hit VMEM if VMEM is set low.
The fix
The configuration:
-
Set VMEM to 0 (unlimited) in the package config:
/etc/container/<package>.yamlvmem: 0 pmem: 1024 # 1 GB physicalApply with
lvectl apply all. -
Set PMEM to the value you actually want to enforce. PMEM caps actual RAM use, which is the meaningful resource on a shared host.
-
Right-size PMEM per workload. A WordPress + WooCommerce site under load needs 1-2 GB PMEM. A simple brochure WordPress can run on 512 MB. Laravel apps often need 2-4 GB depending on traffic and queue workers.
-
Watch for ghost incidents. If VMEM was previously set restrictively and is now relaxed, customers who were silently hitting VMEM will stop seeing PHP errors. Their actual RAM use may not increase — they were getting killed by VMEM despite plenty of PMEM headroom.
-
For the rare workload that genuinely needs VMEM control (some Java or Node apps with bounded heap), set VMEM only on those specific accounts and document why.
After the change, lveinfo --period=24h --show-incidents should show fewer (or zero) memory incidents on previously affected accounts. PHP error logs should show fewer “out of memory” failures.
The summary: on modern CloudLinux, PMEM is the lever; VMEM was a 2010-era tool that does not map to today’s memory behavior. Stack Harbor sets LVE limits per workload as part of cPanel/WHM management.