{"id":1613,"date":"2026-11-05T22:40:31","date_gmt":"2026-11-05T22:40:31","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=1613"},"modified":"2026-11-05T22:40:31","modified_gmt":"2026-11-05T22:40:31","slug":"cgroup-v2-memory-high-watermark-protection-tuning","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/","title":{"rendered":"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS"},"content":{"rendered":"<div style=\"padding:20px\">\n<p>Most guides treat cgroup memory control as one knob: set <code>memory.max<\/code> and let the OOM killer sort it out. cgroup v2 exposes four controls with different semantics, and the most valuable \u2014 <code>memory.high<\/code> \u2014 kills nothing. It throttles the cgroup into direct reclaim, forcing it to give back page cache, and escalates only if the cgroup cannot comply. On a 2-4 GB VPS running three or four services, that is the difference between one slow service and the whole machine dying.<\/p>\n<h2>The four memory controls and what each enforces<\/h2>\n<p>cgroup v2 memory controller files live in the cgroup directory, typically <code>\/sys\/fs\/cgroup\/&lt;unit&gt;\/<\/code> under systemd. Each has distinct behaviour:<\/p>\n<table>\n<tr>\n<th>File<\/th>\n<th>Semantics<\/th>\n<th>Consequence<\/th>\n<\/tr>\n<tr>\n<td>memory.max<\/td>\n<td>Hard limit on total charge (anon + page cache + kernel)<\/td>\n<td>Reclaim attempted; OOM kill on failure<\/td>\n<\/tr>\n<tr>\n<td>memory.high<\/td>\n<td>Throttle threshold<\/td>\n<td>Direct reclaim, slowed allocations, no kill<\/td>\n<\/tr>\n<tr>\n<td>memory.low<\/td>\n<td>Best-effort protection from global reclaim<\/td>\n<td>Bias only; not a reservation, can be overridden<\/td>\n<\/tr>\n<tr>\n<td>memory.min<\/td>\n<td>Hard protection from reclaim<\/td>\n<td>Pages are never reclaimed while the cgroup exists<\/td>\n<\/tr>\n<\/table>\n<p><code>memory.max<\/code> is the wall, <code>memory.high<\/code> the speed bump before it, <code>memory.low<\/code> a suggestion to the reclaim algorithm, and <code>memory.min<\/code> a real reservation. Most incidents on small VPS instances come from setting only <code>memory.max<\/code> and never reclaiming the 400 MB of cache the application was holding.<\/p>\n<h2>How throttling actually happens under memory.high<\/h2>\n<p>When a cgroup&#8217;s charge crosses <code>memory.high<\/code>, each subsequent allocation must trigger reclaim proportional to how far over it is. The kernel does not run the OOM killer; it makes the allocating task reclaim synchronously, so the application stalls inside <code>malloc<\/code> or a page fault. Reclaim order matters: clean page cache first, then dirty pages written back and dropped, then file-backed executable pages, then anonymous pages pushed to swap. If swap is unavailable \u2014 common on small plans \u2014 anonymous memory cannot be reclaimed and the cgroup can only shrink its cache. Once there is nothing left, the next allocation hits <code>memory.max<\/code>.<\/p>\n<pre>\ncat \/sys\/fs\/cgroup\/myservice\/memory.current\ncat \/sys\/fs\/cgroup\/myservice\/memory.high\ncat \/sys\/fs\/cgroup\/myservice\/memory.events\n# memory.events shows: low high max oom oom_kill oom_group_kill\n<\/pre>\n<p><code>memory.events<\/code> is the audit trail. Rising <code>high<\/code> with stable <code>oom_kill<\/code> means throttling works. <code>max<\/code> incrementing means you hit the wall and reclaim failed; <code>oom_kill<\/code> incrementing means something died.<\/p>\n<h2>Page cache reclaim is the point, not a side effect<\/h2>\n<p>On a 2 GB box, a Node.js or Java service that reads many files accumulates hundreds of megabytes of page cache. That cache counts in <code>memory.current<\/code> but is free memory \u2014 dropping it costs a re-read. Setting <code>memory.high<\/code> at 85-90 percent of <code>memory.max<\/code> makes the service eat its own cache before the system comes under pressure.<\/p>\n<p>Without <code>memory.high<\/code>, global pressure reclaims proportionally across cgroups, so your database&#8217;s hot pages get dropped to make room for a build job. <code>memory.low<\/code> biases reclaim away from the database but only as a weight; <code>memory.min<\/code> is the only guarantee.<\/p>\n<pre>\n# systemd drop-in for a 2 GB box, service capped at 1.2 GB\n[Service]\nMemoryMax=1200M\nMemoryHigh=1000M\nMemoryLow=400M\nMemorySwapMax=0\n<\/pre>\n<p>Apply with <code>systemctl daemon-reload<\/code> and verify with <code>systemctl show myservice -p MemoryMax -p MemoryHigh<\/code>; <code>cat memory.high<\/code> should return 1048576000 for 1000M.<\/p>\n<h2>Practical thresholds for a 2-4 GB VPS<\/h2>\n<p>Start from resident working sets, not total RAM. Measure each service&#8217;s RSS under realistic load with <code>smem -tk<\/code>, then add 15-25 percent for fragmentation and transient buffers.<\/p>\n<ul>\n<li>2 GB box, single app: MemoryHigh 1.4G, MemoryMax 1.6G, leaving 300-400 MB for the kernel, journald and SSH.<\/li>\n<li>2 GB box with MySQL 512 MB + app: MySQL MemoryLow 400M \/ Max 600M; app High 700M \/ Max 800M.<\/li>\n<li>4 GB box, three services: each High at 80 percent of its Max, and the sum of Max values not exceeding 3.4 GB.<\/li>\n<li>Swap present: set MemorySwapMax to 0 for latency-sensitive services so throttle happens before swap thrash.<\/li>\n<\/ul>\n<p>Never let the sum of <code>memory.max<\/code> equal total RAM: the kernel, page tables and slab need 8-12 percent, and systemd&#8217;s slices take a little too. On a single-service box at the <a href=\"https:\/\/virtualserversvps.com\/\">entry VPS tier<\/a> the exercise often collapses to one number \u2014 <code>memory.high<\/code> at MemTotal minus 400 MB \u2014 so the throttle fires before any host-level balloon or global OOM.<\/p>\n<h2>Verifying with memory.pressure<\/h2>\n<p><code>memory.pressure<\/code> reports the share of wall-clock time tasks were stalled on memory. <code>some<\/code> counts any stalled task, <code>full<\/code> counts periods where every runnable task was stalled \u2014 the signal for whether the throttle worked or just moved the stall elsewhere.<\/p>\n<pre>\ncat \/sys\/fs\/cgroup\/myservice\/memory.pressure\n# some avg10=12.40 avg60=9.10 avg300=4.20 total=88123456\nwhile true; do\n  printf '%s ' \"$(date +%T)\"\n  grep -o 'full avg10=[0-9.]*' \/sys\/fs\/cgroup\/myservice\/memory.pressure\n  sleep 5\ndone\n<\/pre>\n<p>Interpretation for a 2-4 GB box:<\/p>\n<ul>\n<li><code>full avg10<\/code> under 2 percent: healthy, the cgroup has headroom.<\/li>\n<li><code>full avg10<\/code> between 2 and 10 percent: throttle is active; check whether latency matters and raise <code>memory.high<\/code> if p99 user latency is affected.<\/li>\n<li><code>full avg10<\/code> above 20 percent sustained: the working set does not fit; reduce it or resize the plan.<\/li>\n<li>Zero pressure but rising <code>memory.events:max<\/code>: allocations are spiking past the wall between samples; lower <code>memory.high<\/code> so throttling engages earlier.<\/li>\n<\/ul>\n<p>Pair it with <code>\/proc\/pressure\/memory<\/code>: high host-wide pressure alongside low cgroup pressure means the contention is other tenants or a host balloon.<\/p>\n<h2>A tuning sequence that converges in three passes<\/h2>\n<p>Apply this in order \u2014 each pass depends on the observation from the previous one.<\/p>\n<pre>\n# pass 1: observe\nsystemd-cgtop -m --iterations=12\ncat \/sys\/fs\/cgroup\/myservice\/memory.peak\n# pass 2: throttle above observed peak\necho 1100M &gt; \/sys\/fs\/cgroup\/myservice\/memory.high\n# pass 3: hard ceiling with margin\necho 1250M &gt; \/sys\/fs\/cgroup\/myservice\/memory.max\nsystemctl restart myservice &amp;&amp; sleep 300\ngrep -E 'high|max|oom' \/sys\/fs\/cgroup\/myservice\/memory.events\n<\/pre>\n<p><code>memory.peak<\/code> gives the high-water mark since creation \u2014 size <code>memory.high<\/code> from that, about 10 percent above, not from the instantaneous reading. After a week, if <code>high<\/code> is in the millions and <code>oom_kill<\/code> is zero, pressure is being absorbed as latency instead of death. If <code>max<\/code> is climbing, the ceiling is one spike from an OOM. Recording both counters next to your <a href=\"https:\/\/virtualserversvps.com\/\">VPS plan&#8217;s memory allocation<\/a> makes the next resize decision evidence-based.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Most guides treat cgroup memory control as one knob: set memory.max and let the OOM killer sort it out. cgroup v2 exposes four controls with different semantics, and the most&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1613","post","type-post","status-publish","format-standard","hentry","category-performance-optimization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS - Virtual Servers VPS Blog<\/title>\n<meta name=\"description\" content=\"Most guides treat cgroup memory control as one knob: set memory.max and let the OOM killer sort it out. cgroup v2 exposes four controls with different\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS\" \/>\n<meta property=\"og:description\" content=\"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-11-05T22:40:31+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/\",\"name\":\"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-11-05T22:40:31+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"description\":\"Most guides treat cgroup memory control as one knob: set memory.max and let the OOM killer sort it out. cgroup v2 exposes four controls with different\",\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS - Virtual Servers VPS Blog","description":"Most guides treat cgroup memory control as one knob: set memory.max and let the OOM killer sort it out. cgroup v2 exposes four controls with different","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/","og_locale":"en_US","og_type":"article","og_title":"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS","og_description":"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS","og_url":"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-11-05T22:40:31+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/","url":"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/","name":"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-11-05T22:40:31+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"description":"Most guides treat cgroup memory control as one knob: set memory.max and let the OOM killer sort it out. cgroup v2 exposes four controls with different","breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/cgroup-v2-memory-high-watermark-protection-tuning\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"cgroup v2 Memory High and Watermark Protection: Tuning Real Workloads on a VPS"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1613","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=1613"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1613\/revisions"}],"predecessor-version":[{"id":1614,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1613\/revisions\/1614"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=1613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=1613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=1613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}