<p>I have a PHP daemon script downloading remote images and storing them local temporary before uploading to object storage.</p>

<p>PHP internal memory usage remains stable but the memory usage reported by Docker/Kubernetes keeps increasing.</p>

<p>I'm not sure if this is related to PHP, Docker or expected Linux behavior.</p>

<p>Example to reproduce the issue:</p>

<p>Docker image: <code>php:7.2.2-apache</code></p>

<pre><code>&lt;?php
for ($i = 0; $i &lt; 100000; $i++) {
    $fp = fopen('/tmp/' . $i, 'w+');
    fclose($fp);

    unlink('/tmp/' . $i);

    unset($fp);
}
</code></pre>

<p>Calling <code>free -m</code> inside container before executing the above script:</p>

<pre><code>          total        used        free      shared  buff/cache   available
Mem:           3929        2276         139          38        1513        1311
Swap:          1023         167         856
</code></pre>

<p>And after executing the script:</p>

<pre><code>          total        used        free      shared  buff/cache   available
Mem:           3929        2277         155          38        1496        1310
Swap:          1023         167         856
</code></pre>

<p>Apperantly the memory is released but calling <code>docker stats php-apache</code> from host indicate something other:</p>

<pre><code>CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
ccc19719078f        php-apache          0.00%               222.1MiB / 3.837GiB   5.65%               1.21kB / 0B         1.02MB / 4.1kB      7
</code></pre>

<p>The initial memory usage reported by <code>docker stats php-apache</code> was 16.04MiB.</p>

<p>What is the explanation? How do I free the memory?</p>

<p>Having this contianer running in a Kubernetes cluster with resource limits causes the pod to fail and restart repeatedly.</p>

<p>Yes, a similar issue has been reported <a href="https://github.com/moby/moby/issues/10824#issuecomment-347499296" rel="noreferrer">here</a>.</p>

<p><a href="https://github.com/moby/moby/issues/10824#issuecomment-347725280" rel="noreferrer">Here's the answer</a> of coolljt0725, one of the contributors, answering why a <code>RES</code> column in <code>top</code> output shows something different, than <code>docker stats</code> (I'm just gonna quote him as is):</p>

<blockquote>
  <p>If I understand correctly, the memory usage in docker stats is exactly read from containers's memory cgroup, you can see the value is the same with 490270720 which you read from cat /sys/fs/cgroup/memory/docker/665e99f8b760c0300f10d3d9b35b1a5e5fdcf1b7e4a0e27c1b6ff100981d9a69/memory.usage_in_bytes, and the limit is also the memory cgroup limit which is set by -m when you create container. The statistics of RES and memory cgroup are different, the RES does not take caches into account, but the memory cgroup does, that's why MEM USAGE in docker stats is much more than RES in top</p>
</blockquote>

<p>What a user suggested <a href="https://github.com/moby/moby/issues/10824#issuecomment-84771847" rel="noreferrer">here</a> might actually help you to see the real memory consumption:</p>

<blockquote>
  <p>Try set the param of <code>docker run --memory</code>，then check your
  <code>/sys/fs/cgroup/memory/docker/&lt;container_id&gt;/memory.usage_in_bytes</code>
  It should be right.</p>
</blockquote>

<p><code>--memory</code> or <code>-m</code> is described <a href="https://docs.docker.com/engine/reference/run/#runtime-constraints-on-resources" rel="noreferrer">here</a>:</p>

<blockquote>
  <p><code>-m</code>, <code>--memory=""</code> - Memory limit (format: <code>&lt;number&gt;[&lt;unit&gt;]</code>). Number is a positive integer. Unit can be one of <code>b</code>, <code>k</code>, <code>m</code>, or <code>g</code>. Minimum is <code>4M</code>.</p>
</blockquote>

<p>And now how to avoid the unnecessary memory consumption. Just as you posted, unlinking a file in PHP does not necessary drop memory cache immediately. Instead, running the Docker container in privileged mode (with <code>--privileged</code> flag) it is then possible to call <code>echo 3 &gt; /proc/sys/vm/drop_caches</code> or <code>sync &amp;&amp; sysctl -w vm.drop_caches=3</code> periodcally to clear the memory pagecache.</p>

<p>And as a bonus, using <code>fopen('php://temp', 'w+')</code> and storing the file temporary in memory avoids the entire issue.</p>
