{"id":54203,"date":"2025-11-26T06:53:20","date_gmt":"2025-11-26T06:53:20","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=54203"},"modified":"2025-11-26T06:53:20","modified_gmt":"2025-11-26T06:53:20","slug":"dotnet-understanding-memory-leaks-and-debugging-using-dotmemory","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/dotnet-understanding-memory-leaks-and-debugging-using-dotmemory\/","title":{"rendered":"DOTNET: Understanding Memory leaks and Debugging using dotMemory"},"content":{"rendered":"\n<p>I\u2019ll give you:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>One self-contained Program.cs<\/strong> you can drop into a new project<\/li>\n\n\n\n<li><strong>How to run it from command line<\/strong><\/li>\n\n\n\n<li><strong>Step-by-step: how to use dotMemory to detect the leak<\/strong><\/li>\n\n\n\n<li><strong>How to read dotMemory results &amp; locate the leak<\/strong><\/li>\n\n\n\n<li><strong>How to fix it (clean version of the code)<\/strong><\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1\ufe0f\u20e3 Create the demo app<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">dotnet <span class=\"hljs-keyword\">new<\/span> web -n MemoryLeakDemo\ncd MemoryLeakDemo\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now <strong>replace the entire <code>Program.cs<\/code><\/strong> with this:<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/33e129696cb93456f6ee66409adefc9e.js\"><\/script>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\"><\/code><\/span><\/pre>\n\n\n<p>This is <strong>self-sufficient<\/strong>: one file, no extra classes, no extra projects.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2\ufe0f\u20e3 Run the app (command line)<\/h2>\n\n\n\n<p>From the <code>MemoryLeakDemo<\/code> folder:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet run\n<\/code><\/span><\/pre>\n\n\n<p>It will listen on something like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>http:\/\/localhost:5000<\/code><\/li>\n\n\n\n<li><code>https:\/\/localhost:5001<\/code><\/li>\n<\/ul>\n\n\n\n<p>(Use the HTTP one for simplicity: <code>http:\/\/localhost:5000<\/code>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3\ufe0f\u20e3 Generate the leak<\/h2>\n\n\n\n<p>In another terminal (or browser \/ Postman):<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">A. Start leaking memory<\/h3>\n\n\n\n<p>Run a loop (PowerShell):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-number\">1.<\/span><span class=\"hljs-number\">.50<\/span> | ForEach-<span class=\"hljs-built_in\">Object<\/span> {\n    curl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/leak\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Or Git Bash:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">for<\/span> i <span class=\"hljs-keyword\">in<\/span> {<span class=\"hljs-number\">1.<\/span><span class=\"hljs-number\">.50<\/span>}; <span class=\"hljs-keyword\">do<\/span> curl -s <span class=\"hljs-string\">\"http:\/\/localhost:5000\/leak\"<\/span> &gt; <span class=\"hljs-regexp\">\/dev\/<\/span><span class=\"hljs-literal\">null<\/span>; done\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then check stats:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/stats\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You should see <code>Total stored MB<\/code> growing (e.g. 250 MB).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">B. Compare with non-leaking allocations<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-number\">1.<\/span><span class=\"hljs-number\">.50<\/span> | ForEach-<span class=\"hljs-built_in\">Object<\/span> {\n    curl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/noleak\"<\/span>\n}\ncurl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/gc\"<\/span>\ncurl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/stats\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<ul class=\"wp-block-list\">\n<li><code>\/noleak<\/code> allocates memory but <strong>does not store it<\/strong> \u2192 GC can clean it.<\/li>\n\n\n\n<li><code>\/leak<\/code> allocates memory and <strong>keeps it in a static list<\/strong> \u2192 cannot be GC\u2019d.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4\ufe0f\u20e3 Profile with dotMemory \u2013 step by step<\/h2>\n\n\n\n<p>Assuming you have <strong>dotMemory GUI<\/strong> (Rider\/Standalone):<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Start the app<\/h3>\n\n\n\n<p>Make sure <code>dotnet run<\/code> for <code>MemoryLeakDemo<\/code> is running.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Open dotMemory<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Start <strong>dotMemory<\/strong><\/li>\n\n\n\n<li>Choose <strong>\u201cProfile Running Process\u201d<\/strong> (or similar wording)<\/li>\n\n\n\n<li>Select the <code>dotnet.exe<\/code> \/ <code>MemoryLeakDemo.dll<\/code> process<\/li>\n\n\n\n<li>Click <strong>Run<\/strong> \/ <strong>Attach<\/strong><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Take a baseline snapshot<\/h3>\n\n\n\n<p>In dotMemory:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Click <strong>\u201cGet Snapshot\u201d<\/strong> (or \u201cGet Snapshot #1\u201d).<\/li>\n\n\n\n<li>Name it \u201cBaseline (before leak)\u201d.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Generate the leak<\/h3>\n\n\n\n<p>Back in terminal:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-number\">1.<\/span><span class=\"hljs-number\">.100<\/span> | ForEach-<span class=\"hljs-built_in\">Object<\/span> {\n    curl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/leak\"<\/span>\n}\ncurl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/stats\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You should see big total MB stored.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Take snapshot after leak<\/h3>\n\n\n\n<p>In dotMemory:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Click <strong>\u201cGet Snapshot\u201d<\/strong> again.<\/li>\n\n\n\n<li>Name it \u201cAfter leak (static list)\u201d.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Optionally, force GC and snapshot<\/h3>\n\n\n\n<p>Back in terminal:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/gc\"<\/span>\ncurl <span class=\"hljs-string\">\"http:\/\/localhost:5000\/stats\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then in dotMemory:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Take <strong>Snapshot #3<\/strong>: \u201cAfter GC\u201d.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5\ufe0f\u20e3 Understanding dotMemory results (how to spot the leak)<\/h2>\n\n\n\n<p>Now the fun part: <strong>reading dotMemory<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">A. Compare snapshots (Baseline vs After leak)<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>In dotMemory, select \u201cBaseline\u201d and \u201cAfter leak\u201d snapshots.<\/li>\n\n\n\n<li>Click <strong>\u201cCompare Snapshots\u201d<\/strong>.<\/li>\n<\/ol>\n\n\n\n<p>Look at:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Heap size increased a lot<\/strong><\/li>\n\n\n\n<li><strong>New objects count<\/strong> is huge<\/li>\n\n\n\n<li>Top types by size will likely show <strong><code>System.Byte[]<\/code><\/strong> (byte arrays)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">B. Drill into <code>byte[]<\/code> and find retention<\/h3>\n\n\n\n<p>Click on <code>System.Byte[]<\/code> and open:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u201cRetention Graph\u201d<\/strong><\/li>\n\n\n\n<li>or <strong>\u201cShortest Paths to GC Roots\u201d<\/strong><\/li>\n<\/ul>\n\n\n\n<p>You should see a path like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">Static<\/span> <span class=\"hljs-selector-tag\">field<\/span> \u2192 <span class=\"hljs-selector-tag\">LeakStore<\/span><span class=\"hljs-selector-class\">.Buffers<\/span> \u2192 <span class=\"hljs-selector-tag\">List<\/span>&lt;<span class=\"hljs-selector-tag\">byte<\/span><span class=\"hljs-selector-attr\">&#91;]<\/span>&gt; \u2192 <span class=\"hljs-selector-tag\">byte<\/span><span class=\"hljs-selector-attr\">&#91;]<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This tells you:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <code>byte[]<\/code> objects are <strong>alive<\/strong> because they are referenced by a static list.<\/li>\n\n\n\n<li>That static list is <code>LeakStore.Buffers<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>This is your <strong>memory leak<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">C. Check what happens after GC<\/h3>\n\n\n\n<p>Compare \u201cAfter leak\u201d vs \u201cAfter GC\u201d snapshots:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If <code>byte[]<\/code> objects are still around in large numbers\/size \u2192 GC cannot free them.<\/li>\n\n\n\n<li>Why? Because they\u2019re still referenced by <code>LeakStore.Buffers<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>That is exactly how dotMemory exposes <strong>real leaks<\/strong>:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Objects survive GCs and are retained by long-lived references (statics, singletons, caches, events, etc.).<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6\ufe0f\u20e3 Common real-world patterns similar to this leak<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Static lists\/dictionaries that grow but never shrink<\/li>\n\n\n\n<li>Caches without eviction policies<\/li>\n\n\n\n<li>Event handlers where you forget to <code>-=<\/code> unsubscribe<\/li>\n\n\n\n<li>Long-lived singletons holding request-scoped data<\/li>\n\n\n\n<li><code>Task<\/code> or <code>Timer<\/code> callbacks closing over large objects<\/li>\n\n\n\n<li>In-memory queues that never get drained<\/li>\n<\/ul>\n\n\n\n<p>dotMemory will show all of these as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Big retained size<\/li>\n\n\n\n<li>GC roots pointing to static fields, singletons, or event tables<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7\ufe0f\u20e3 How to fix this leak (clean code version)<\/h2>\n\n\n\n<p>Here\u2019s a <strong>fixed version<\/strong> of the leak part:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Option A: Limit the cache<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">LeakStore<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">const<\/span> int MaxBuffers = <span class=\"hljs-number\">10<\/span>;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> readonly Queue&lt;byte&#91;]&gt; Buffers = <span class=\"hljs-keyword\">new<\/span>();\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> void AddBuffer(byte&#91;] buffer)\n    {\n        Buffers.Enqueue(buffer);\n        <span class=\"hljs-keyword\">while<\/span> (Buffers.Count &gt; MaxBuffers)\n        {\n            Buffers.Dequeue(); <span class=\"hljs-comment\">\/\/ old buffers become eligible for GC<\/span>\n        }\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> int Count =&gt; Buffers.Count;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then in <code>\/leak<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">var<\/span> buffer = <span class=\"hljs-keyword\">new<\/span> byte&#91;bytes];\n<span class=\"hljs-comment\">\/\/ ...<\/span>\nLeakStore.AddBuffer(buffer);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now dotMemory will show:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Heap size <em>not<\/em> growing unbounded<\/li>\n\n\n\n<li>Byte arrays being collected over time<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Option B: Don\u2019t use static leaks at all<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use scoped dependencies<\/li>\n\n\n\n<li>Avoid unbounded global collections<\/li>\n\n\n\n<li>Use proper cache with TTL \/ LRU (e.g., MemoryCache)<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">8\ufe0f\u20e3 In-Code Metrics (like we did for TLS)<\/h2>\n\n\n\n<p>For this example, <code>\/stats<\/code> already gives:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Number of stored buffers<\/li>\n\n\n\n<li>Total MB stored<\/li>\n\n\n\n<li>Number of leak calls<\/li>\n<\/ul>\n\n\n\n<p>You can show this in the terminal while dotMemory shows <strong>heap graph growth<\/strong> \u2192 this connects code behavior + profiler view.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I\u2019ll give you: 1\ufe0f\u20e3 Create the demo app Now replace the entire Program.cs with this: This is self-sufficient: one file, no extra classes, no extra projects. 2\ufe0f\u20e3 Run the app&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-54203","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54203","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=54203"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54203\/revisions"}],"predecessor-version":[{"id":54204,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54203\/revisions\/54204"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=54203"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=54203"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=54203"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}