std_alloc memory leak

Hello. Does anybody have any ideas how to debug standard allocator memory leak. Standard allocator is used by a lot of different types of data, and I have no ideas how to find the real problem.

Now out production service leak for about 200MB every day.

> recon_alloc:memory(allocated_types).
[{binary_alloc,173309952},
 {driver_alloc,2392064},
 {eheap_alloc,256114688},
 {ets_alloc,155713536},
 {fix_alloc,7897088},
 {ll_alloc,35913728},
 {sl_alloc,294912},
 {std_alloc,1_883_799_552}, %1.8GB
 {temp_alloc,1179648}]

Check if you are not leaking processes or atoms. As far as I know, the process registry for named processes goes to that table, and if you are leaking atoms on defining named processes at runtime that might be the problem.

Thanks, but it is not that case

> length(erlang:registered()).
208

> erlang:memory(atom).
801721

Now I’m going to enable intrumentation (http://erlang.org/doc/man/instrument.html) for std_alloc with +MDatags (it is not enabled by default) and see

Does any one process or group of processes show high memory usage?

No, memory used by system, not processes

1> erlang:memory().
[{total,2319419608},
 {processes,109_996_352}, %100MB there
 {processes_used,109_905_152}, 
 {system,2_209_423_256}, %2GB there
 {atom,801721},
 {atom_used,800062},
 {binary,58644280},
 {code,14224484},
 {ets,80701752}]

Have you read the online/free Erlang in Anger book? It is about debugging BEAM systems and has a section about debugging this specific kind of issue as I recall. :slight_smile:

9. std_alloc: catch-all allocator for whatever didn't fit the previous categories. The 
process registry for named process is there. 

By default, there will be one instance of each allocator per scheduler (and you should 
have one scheduler per core), plus one instance to be used by linked-in drivers using async 
threads. This ends up giving you a structure a bit like in Figure 7.1, but split it in N parts 
at each leaf. 

Each of these sub-allocators will request memory from mseg_alloc and sys_alloc 
depending on the use case, and in two possible ways. The first way is to act as a multiblock 
carrier (mbcs), which will fetch chunks of memory that will be used for many Erlang terms 
at once. For each mbc, the VM will set aside a given amount of memory (about 8MB 
by default in our case, which can be configured by tweaking VM options), and each term 
allocated will be free to go look into the many multiblock carriers to find some decent space 
in which to reside. 

Whenever the item to be allocated is greater than the single block carrier threshold 
(sbct) 15 , the allocator switches this allocation into a single block carrier (sbcs). A single 
block carrier will request memory directly from mseg_alloc for the first mmsbc 16 entries, 
and then switch over to sys_alloc and store the term there until it's deallocated. 

So looking at something such as the binary allocator, we may end up with something 
similar to Figure 7.2 

15 http://erlang.org/doc/man/erts_alloc.html#M_sbct 
16 http://erlang.org/doc/man/erts_alloc.html#M_mmsbc 

See whole book for details.

There is no information about leak capabilities for std_alloc

After enabling memory instrumentations for std_alloc I’ve found this

> instrument:allocations(#{allocator_types => [std_alloc]}).

re_heap =>
{0,0,0,3118,31206,97417,63424,22618,5786,0,0,0,0,0,0,0,0,0},

Our service recompile thousand regexp from time to time and store in into ets, but each time it deletes old regexps, so no memory leak should be. Will try to research further

2 Likes