<div dir="ltr"><font face="monospace, monospace">Hi All,</font><div><font face="monospace, monospace"><br></font></div><div><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">Recently, we found the server which hosts horizon dashboard had serveral times OOM caused by horizon services. After restarting the dashboard, the memory usage goes up very quickly if we access /project/network_topology/ path.</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><b><font face="monospace, monospace">How to reproduce</font></b></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">Login into the dashboard and go to 'Network Topology' tab, then leave it there (autorefresh 10s by default), now monitor the memory changes on the host.</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><b><font face="monospace, monospace">Versions and Components</font></b></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">Dashboard: Stable/Pike<br>Server: uWSGI 1.9.17-1<br>OS: Ubuntu 14.04 trusty<br>Python: 2.7.6</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">As the codes of memoized has little changes since Pike, if you use Queen/Rocky release, you may also succeed to reproduce it.</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><b><font face="monospace, monospace">The investigation</font></b></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">The root cause of the memory leak is the decorator memorized(horizon/utils/memoized.py) which is used to cache function calls in Horizon.</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">After disable it, the memory increases has been controlled.</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">The following is the comparison of memory change(with guppy) for each request of /project/network_topology:</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace"> - original (no code change) 684kb</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace"> - do garbage collection manually 185kb</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace"> - disable memorize cache 10kb</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">As we known, memoized uses weakref to cache objects. A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else.</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">In the memory, we could see lots of weakref stuffs, the following is a example:</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><i><font face="monospace, monospace">Partition of a set of 394 objects. Total size = 37824 bytes.<br> Index Count % Size % Cumulative % Kind (class / dict of class)<br>     0 197 50 18912 50 18912 50 _cffi_backend.CDataGCP<br>     1 197 50 18912 50 37824 100 weakref.KeyedRefq</font></i></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">But the rest of them are not. the following result is the memory objects changes of per /project/network_topology access with garbage collection manually.</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><i><font face="monospace, monospace">Partition of a set of 1017 objects. Total size = 183680 bytes.<br> Index Count % Size % Cumulative % Referrers by Kind (class / dict of class)<br>     0 419 41 58320 32 58320 32 dict (no owner)<br>     1 100 10 23416 13 81736 44 list<br>     2 135 13 15184 8 96920 53 <Nothing><br>     3 2 0 6704 4 103624 56 urllib3.connection.VerifiedHTTPSConnection<br>     4 2 0 6704 4 110328 60 urllib3.connectionpool.HTTPSConnectionPool<br>     5 1 0 3352 2 113680 62 novaclient.v2.client.Client<br>     6 2 0 2096 1 115776 63 OpenSSL.SSL.Connection<br>     7 2 0 2096 1 117872 64 OpenSSL.SSL.Context<br>     8 2 0 2096 1 119968 65 Queue.LifoQueue<br>     9 12 1 2096 1 122064 66 dict of urllib3.connectionpool.HTTPSConnectionPool</font></i></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">The most of them are dicts. Followings are the dicts sorted by class, as you can see most of them are not weakref objects:</font></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><i><font face="monospace, monospace">Partition of a set of 419 objects. Total size = 58320 bytes.<br> Index Count % Size % Cumulative % Class<br>     0 362 86 50712 87 50712 87 unicode<br>     1 27 6 3736 6 54448 93 list<br>     2 5 1 2168 4 56616 97 dict<br>     3 22 5 1448 2 58064 100 str<br>     4 2 0 192 0 58256 100 weakref.KeyedRef<br>     5 1 0 64 0 58320 100 keystoneauth1.discover.Discover</font></i></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><b><font face="monospace, monospace">The issue</font></b></p><p style="margin:0px 0px 1.2em;padding:0px;width:auto;max-width:45em;color:rgb(51,51,51);font-size:12px"><font face="monospace, monospace">So the problem is that memoized does not work like what we expect. It allocates memory to cache objects but some of them could not be released.</font></p></div></div>