<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Systemd on KDE Blogs</title><link>https://blogs.kde.org/categories/systemd/</link><description>Recent content in Systemd on KDE Blogs</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 31 Mar 2026 18:04:10 +0300</lastBuildDate><atom:link href="https://blogs.kde.org/categories/systemd/index.xml" rel="self" type="application/rss+xml"/><item><title>Limit Application Memory Usage with systemd</title><link>https://blogs.kde.org/2024/10/18/limit-application-memory-usage-with-systemd/</link><pubDate>Fri, 18 Oct 2024 10:00:00 +0000</pubDate><author>Jin Liu</author><guid>https://blogs.kde.org/2024/10/18/limit-application-memory-usage-with-systemd/</guid><description>&lt;p&gt;I saw this &lt;a href="https://discuss.kde.org/t/how-to-limit-memory-size-used-by-specific-application-in-kde/23565"&gt;question on KDE forum&lt;/a&gt; about how to limit memory usage of a specific application in KDE, using systemd specifically. I did some research on that.&lt;/p&gt;
&lt;h2 id="resource-control-in-systemd"&gt;Resource control in systemd&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html"&gt;man systemd.resource-control&lt;/a&gt; lists plenty of options that we can set to a &lt;em&gt;cgroup&lt;/em&gt;. E.g., to limit the memory usage of a service, we can add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;MemoryAccounting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;MemoryHigh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2G&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;under the &lt;code&gt;[Service]&lt;/code&gt; section of its &lt;code&gt;.service&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The difference between this and &lt;code&gt;ulimit&lt;/code&gt; is that &lt;code&gt;ulimit&lt;/code&gt; is per process, while systemd resource control is per &lt;em&gt;cgroup&lt;/em&gt;. I.e., the &lt;code&gt;MemoryHigh&lt;/code&gt; is accounted to the sum of both the service process, and all sub-processes it spawns, and even detached processes, i.e., daemons.&lt;/p&gt;
&lt;p&gt;(That's actually the main point of &lt;em&gt;cgroup&lt;/em&gt;: a process tree that a process can't escape via double-forking / daemonizing.)&lt;/p&gt;
&lt;h2 id="apps-as-systemd-services"&gt;Apps as systemd services&lt;/h2&gt;
&lt;p&gt;KDE Plasma launches apps as systemd services. (See &lt;a href="https://systemd.io/DESKTOP_ENVIRONMENTS/"&gt;this doc&lt;/a&gt; and &lt;a href="https://blog.davidedmundson.co.uk/blog/modern-process-management-on-the-desktop/"&gt;this blog&lt;/a&gt; for more details.)&lt;/p&gt;
&lt;p&gt;We can find the name of the systemd service of an app like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemd-cgls&lt;span class="p"&gt;|&lt;/span&gt;grep konsole
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ │ ├─app-org.kde.konsole@0d82cb37fcd64fe4a8b7cf925d86842f.service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ │ │ ├─35275 /usr/bin/konsole
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ │ │ └─35471 grep --color&lt;span class="o"&gt;=&lt;/span&gt;auto konsole
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the problem is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The part of the name after &lt;code&gt;@&lt;/code&gt; is a random string, changes every time the app is launched.&lt;/li&gt;
&lt;li&gt;The service is generated dynamically:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemctl --user cat app-org.kde.konsole@0d82cb37fcd64fe4a8b7cf925d86842f.service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /run/user/1000/systemd/transient/app-org.kde.konsole@0d82cb37fcd64fe4a8b7cf925d86842f.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# This is a transient unit file, created programmatically via the systemd API. Do not edit.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;simple
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So if we want to limit the memory usage of Konsole, there's no persistent &lt;code&gt;.service&lt;/code&gt; file on disk that we can edit.&lt;/p&gt;
&lt;p&gt;Luckily, systemd allows us to create &lt;em&gt;drop-in&lt;/em&gt; files to partially modify a service. Also, systemd considers &lt;code&gt;app-org.kde.konsole@0d82cb37fcd64fe4a8b7cf925d86842f.service&lt;/code&gt; to be instances of a &lt;em&gt;template&lt;/em&gt; named &lt;code&gt;app-org.kde.konsole@.service&lt;/code&gt;. (This is how things like &lt;code&gt;getty@tty3.service&lt;/code&gt; work.) So we can create a drop-in file named &lt;code&gt;~/.config/systemd/user/app-org.kde.konsole@.service.d/override.conf&lt;/code&gt; with the content:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;MemoryAccounting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;MemoryHigh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2G&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and it will apply to all instances of &lt;code&gt;app-org.kde.konsole@.service&lt;/code&gt;, even if there's no service file with that name.&lt;/p&gt;
&lt;p&gt;(The file doesn't have to be named &amp;quot;override.conf&amp;quot;. Any name with &lt;code&gt;.conf&lt;/code&gt; works.)&lt;/p&gt;
&lt;p&gt;Then we need to reload the systemd user manager: &lt;code&gt;systemctl --user daemon-reload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can launch Konsole, and check if the memory limit works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemctl --user show &lt;span class="s1"&gt;&amp;#39;app-org.kde.konsole@*.service&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;grep &lt;span class="nv"&gt;MemoryHigh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;EffectiveMemoryHigh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2147483648&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;MemoryHigh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2147483648&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;StartupMemoryHigh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;infinity
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: as explained above, the limit applies to the sum of Konsole and all processes it spawns. E.g., if we run &lt;code&gt;kwrite&lt;/code&gt; in Konsole, the memory usage of &lt;code&gt;kwrite&lt;/code&gt; will be accounted to the limit of Konsole, and the limit we set to KWrite won't apply.&lt;/p&gt;
&lt;h2 id="set-defaults-for-all-apps"&gt;Set defaults for all apps&lt;/h2&gt;
&lt;p&gt;We can put defaults in &lt;code&gt;~/.config/systemd/user/app-.service.d/override.conf&lt;/code&gt;, and it will match all services whose name starts with &lt;code&gt;app-&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, if we run &lt;code&gt;systemd-cgls&lt;/code&gt;, we can see that all apps are under a node named &lt;code&gt;app.slice&lt;/code&gt;. So we can also put defaults in &lt;code&gt;~/.config/systemd/user/app.slice.d/override.conf&lt;/code&gt;, and all apps will inherit the settings. However, this is different from the previous method, as user services are also under &lt;code&gt;app.slice&lt;/code&gt; by default, so they will also inherit the settings.&lt;/p&gt;</description></item></channel></rss>