{"id":87,"date":"2013-05-21T19:22:41","date_gmt":"2013-05-21T17:22:41","guid":{"rendered":"http:\/\/blog.ramses-pyramidenbau.de\/?p=87"},"modified":"2013-05-21T19:38:04","modified_gmt":"2013-05-21T17:38:04","slug":"linuxs-strange-memory-allocation-strategy","status":"publish","type":"post","link":"https:\/\/blog.vmexit.de\/?p=87","title":{"rendered":"Linux&#8217;s strange memory allocation strategy"},"content":{"rendered":"<p><a title=\"Why does malloc() or new never return NULL?\" href=\"http:\/\/stackoverflow.com\/questions\/16674370\/why-does-malloc-or-new-never-return-null\">As I learned today<\/a>, Linux has a real strange memory allocation strategy. Have a look at this piece of code:<\/p>\n<pre class=\"brush: cpp; light: true; title: ; notranslate\" title=\"\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n\r\nint main(void) {\r\n  while(1) {\r\n    char *foo = (char*)malloc(1024);\r\n    if(foo == NULL) {\r\n      printf(&quot;Couldn't alloc\\n&quot;);\r\n      fflush(stdout);\r\n      return 0;\r\n    }\r\n  }\r\n  return 0;\r\n}\r\n<\/pre>\n<p>According to the <a title=\"malloc reference\" href=\"http:\/\/www.cplusplus.com\/reference\/cstdlib\/malloc\/?kw=malloc\">malloc reference<\/a> it should return <strong>NULL<\/strong> if it is not able to allocate memory:<\/p>\n<blockquote><p>&#8220;If the function failed to allocate the requested block of memory, a <i>null pointer<\/i> is returned.&#8221;<\/p><\/blockquote>\n<p>So I thought my process would write <strong>Couldn&#8217;t alloc<\/strong> to <em>stdout<\/em> and exit in a proper way. But it didn&#8217;t act that way. When my system ran out of memory the process got killed by the kernel with signal SIGKILL. So why does it act like this? Wikipedia writes about <a title=\"Out of Memory Wikipedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/Out_of_memory\">Out of memory<\/a>:<\/p>\n<blockquote><p>&#8220;A process which exceeds its per-process limit and then attempts to allocate further memory &#8211; with <code><a class=\"mw-redirect\" title=\"Malloc\" href=\"http:\/\/en.wikipedia.org\/wiki\/Malloc\">malloc<\/a>()<\/code>, for example &#8211; will return failure. A well-behaved application should handle this situation gracefully; however, many do not. An attempt to allocate memory without checking the result is known as an &#8220;unchecked malloc&#8221;.&#8221;<\/p><\/blockquote>\n<p>Well&#8230; Yes&#8230; Of course, you always should check <strong>malloc()<\/strong> if it returned <strong>NULL<\/strong>, but under normal conditions it never will return <strong>NULL<\/strong> because of Linux&#8217;s <em><a title=\"OOM\" href=\"http:\/\/www.win.tue.nl\/~aeb\/linux\/lk\/lk-9.html#ss9.6\">memory overcommitting<\/a><\/em>. By default Linux has an optimistic memory allocation strategy. When allocating memory, <strong>malloc()<\/strong> will return a pointer. The space on the heap which is needed for that pointer gets allocated at the first read\/write operation to that address. In my opinion, this is a really strange behaviour, because when memory gets allocated, it will actually be used. Here&#8217;s a short example to see the effects of that strange behaviour:<\/p>\n<pre class=\"brush: cpp; light: true; title: ; notranslate\" title=\"\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;string.h&gt;\r\n\r\n#define MALLOC_SIZE (1024*1024*10)\r\n\r\nint main(void) {\r\n  int i = 0;\r\n  while(1) {\r\n    char *foo = (char*)malloc(MALLOC_SIZE);\r\n    \/\/memset(foo, 0xaa, MALLOC_SIZE);\r\n    printf(&quot;Allocation No. %d\\n&quot;, i++);\r\n    if(foo == NULL) {\r\n      printf(&quot;Couldn't alloc\\n&quot;);\r\n      fflush(stdout);\r\n      return 0;\r\n    }\r\n  }\r\n  return 0;\r\n}\r\n<\/pre>\n<p>With the <strong>memset<\/strong> line commented out it results to:<\/p>\n<pre class=\"brush: plain; light: true; title: ; notranslate\" title=\"\">\r\nralf@Pegasus:C$ .\/test|tail\r\nAllocation No. 1841101\r\nAllocation No. 1841102\r\nAllocation No. 1841103\r\nAllocation No. 1841104\r\nAllocation No. 1841105\r\nAllocation No. 1841106\r\nAllocation No. 1841107\r\nAllocation No. 1841108\r\nAllocation No. 1841109\r\nAllocation Nzsh: killed     .\/test |\r\nzsh: done       tail\r\n<\/pre>\n<p>And with the <strong>memset<\/strong> commented in it results to:<\/p>\n<pre class=\"brush: plain; light: true; title: ; notranslate\" title=\"\">\r\nralf@Pegasus:C$ .\/test|tail\r\nAllocation No. 1275\r\nAllocation No. 1276\r\nAllocation No. 1277\r\nAllocation No. 1278\r\nAllocation No. 1279\r\nAllocation No. 1280\r\nAllocation No. 1281\r\nAllocation No. 1282\r\nAllocation No. 1283\r\nAllocazsh: killed     .\/test |\r\nzsh: done       tail\r\n<\/pre>\n<p>This is really funny. You can allocate tons of space you don&#8217;t have. That&#8217;s creepy. But this behaviour can be switched by<\/p>\n<pre class=\"brush: bash; light: true; title: ; notranslate\" title=\"\">\r\necho 2 &gt; \/proc\/sys\/vm\/overcommit_memory\r\n<\/pre>\n<blockquote><p>&#8220;Since 2.5.30 the values are: 0 (default): as before: guess about how much overcommitment is reasonable, 1: never refuse any malloc(), 2: be precise about the overcommit &#8211; never commit a virtual address space larger than swap space plus a fraction overcommit_ratio of the physical memory. Here \/proc\/sys\/vm\/overcommit_ratio (by default 50) is another user-settable parameter. It is possible to set overcommit_ratio to values larger than 100. (See also Documentation\/vm\/overcommit-accounting.)&#8221; <a href=\"http:\/\/www.win.tue.nl\/~aeb\/linux\/lk\/lk-9.html\">Source<\/a><\/p><\/blockquote>\n<p>Then, both results (with and without <strong>memset<\/strong>) lead to:<\/p>\n<pre class=\"brush: plain; light: true; title: ; notranslate\" title=\"\">\r\nralf@Pegasus:C$ .\/test|tail\r\nAllocation No. 433\r\nAllocation No. 434\r\nAllocation No. 435\r\nAllocation No. 436\r\nAllocation No. 437\r\nAllocation No. 438\r\nAllocation No. 439\r\nAllocation No. 440\r\nAllocation No. 441\r\nCouldn't alloc\r\n<\/pre>\n<p>And this is exactly what I originally expected to be the <em>normal way<\/em>. Without this bypass, <strong>malloc<\/strong> will never return <strong>NULL<\/strong> and a process will not be able to shut down properly if the system runs out of memory.<\/p>\n<p><a href=\"http:\/\/lwn.net\/Articles\/104185\/\">Here<\/a>&#8216;s a nice anecdote on that topic.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As I learned today, Linux has a real strange memory allocation strategy. Have a look at this piece of code: #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; int main(void) { while(1) { char *foo = (char*)malloc(1024); if(foo == NULL) { printf(&quot;Couldn&#8217;t alloc\\n&quot;); fflush(stdout); return 0; } } return 0; } According to the malloc reference it should return &hellip; <a href=\"https:\/\/blog.vmexit.de\/?p=87\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Linux&#8217;s strange memory allocation strategy<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,7,6],"tags":[],"class_list":["post-87","post","type-post","status-publish","format-standard","hentry","category-c","category-kernel","category-linux"],"_links":{"self":[{"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=\/wp\/v2\/posts\/87","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=87"}],"version-history":[{"count":38,"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=\/wp\/v2\/posts\/87\/revisions"}],"predecessor-version":[{"id":123,"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=\/wp\/v2\/posts\/87\/revisions\/123"}],"wp:attachment":[{"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=87"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=87"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.vmexit.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=87"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}