Why am I seeing RefcBinary with length < 64?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Why am I seeing RefcBinary with length < 64?

Roger Lipscombe-2
Everything I've read on the subject of garbage collecting Erlang
binaries says that binaries > 64 octets are stored off-heap.

If I dump (using gdb and etp-offheapdump -- patched for 64-bits) the
off-heap binaries for a given process, I get something like the
following:

[#RefcBinary<0x10,0x7f6b17079e08,0x7f6b39700560,0x7f6b39700578,(nil)>,
 #RefcBinary<0x10,0x7f6b17079d68,0x7f6b39448c70,0x7f6b39448c88,(nil)>,
 #RefcBinary<0xc,0x7f6b17079fb8,0x7f6c11c8c548,0x7f6c11c8c565,(nil)>,

All in all, there are about 19.5K of them for this particular process.
But they're all 0xc, 0x10 or 0x18 bytes in length.

Mathematically astute readers will note that all three of those
numbers are less than 64.

Why are these binaries being stored off-heap? Is it bad? How do I make
it store them in the process heap?

Background: the process in question is a custom supervisor; it stores
its children in a list of records; it starts processes in response to
a gen_server:call from another node; the binaries are identifiable as
the various startup arguments passed when starting the processes.

Background background: we're running out of memory (the node hits ~9GB
resident), either because the beam is hoarding binaries, or because
the binary heap is hugely fragmented. I'm trying to figure out which
and solve the problem.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Why am I seeing RefcBinary with length < 64?

Jan Chochol-2
Hi,

It is possible that these binaries comes as part of larger binaries (also called sub binaries).
Sub binaries only store reference to originating binary and length - it also mean, that originating binary can not be freed.

You can use binary:copy/1 to convert sub binary to fresh new binary (witch will be stored on heap in case of small binaries).

Regards,
Jan

On Wed, Dec 20, 2017 at 3:24 PM, Roger Lipscombe <[hidden email]> wrote:
Everything I've read on the subject of garbage collecting Erlang
binaries says that binaries > 64 octets are stored off-heap.

If I dump (using gdb and etp-offheapdump -- patched for 64-bits) the
off-heap binaries for a given process, I get something like the
following:

[#RefcBinary<0x10,0x7f6b17079e08,0x7f6b39700560,0x7f6b39700578,(nil)>,
 #RefcBinary<0x10,0x7f6b17079d68,0x7f6b39448c70,0x7f6b39448c88,(nil)>,
 #RefcBinary<0xc,0x7f6b17079fb8,0x7f6c11c8c548,0x7f6c11c8c565,(nil)>,

All in all, there are about 19.5K of them for this particular process.
But they're all 0xc, 0x10 or 0x18 bytes in length.

Mathematically astute readers will note that all three of those
numbers are less than 64.

Why are these binaries being stored off-heap? Is it bad? How do I make
it store them in the process heap?

Background: the process in question is a custom supervisor; it stores
its children in a list of records; it starts processes in response to
a gen_server:call from another node; the binaries are identifiable as
the various startup arguments passed when starting the processes.

Background background: we're running out of memory (the node hits ~9GB
resident), either because the beam is hoarding binaries, or because
the binary heap is hugely fragmented. I'm trying to figure out which
and solve the problem.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Why am I seeing RefcBinary with length < 64?

Roger Lipscombe-2
On 20 December 2017 at 14:32, Jan Chochol <[hidden email]> wrote:
> Hi,
>
> It is possible that these binaries comes as part of larger binaries (also
> called sub binaries).

Is there any way to figure this out in gdb?

> Some information are available at
> http://erlang.org/doc/efficiency_guide/binaryhandling.html .
> Sub binaries only store reference to originating binary and length - it also
> mean, that originating binary can not be freed.

Would I be correct in assuming that, because these binaries come
directly from a cross-node gen_server:call, there *is* no large binary
for them to be sub-binaries of? Or are they sub-binaries of the
cross-node message?

> You can use binary:copy/1 to convert sub binary to fresh new binary (witch
> will be stored on heap in case of small binaries).

Yeah. I've seen that. Before I add these to arbitrary places all over
my code, I'd rather figure out the root cause.

Thanks,
Roger.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Why am I seeing RefcBinary with length < 64?

Lukas Larsson-8
On Wed, Dec 20, 2017 at 3:52 PM, Roger Lipscombe <[hidden email]> wrote:
On 20 December 2017 at 14:32, Jan Chochol <[hidden email]> wrote:
> Hi,
>
> It is possible that these binaries comes as part of larger binaries (also
> called sub binaries).

Is there any way to figure this out in gdb?

You have to check the size in the ProcBin vs the size of the Binary. The Binary is what is pointed to by the second to last pointer value in the dump.

eg:

(gdb) etp-offheapdump ((Process*)0x7fffb53852d8)->off_heap.first
warning: Expression is not an assignment (and might have no effect)
% Offheap dump:
[#RefcBinary<0x3,0x7fffb1cc2460,0x7fffb1841aa8,0x7fffb1841ac0,(nil)>,
 #RefcBinary<0x1f,(nil),0x7fffb1841618,0x7fffb1841630,(nil)>].
(gdb) p *((Binary*)0x7fffb1841aa8)
$1 = {intern = {flags = 0, refc = {counter = 1}}, orig_size = 3, orig_bytes = "1"}

and yes, that size can be smaller than 64 bytes. These < 64 byte binaries are created by the runtime when it needs a binaries that a GC will not move for whatever reason. One such example would be unicode:characters_to_binary/2, which is the reason why the example above only has a 3 byte refc. I'm sure there are others as well. I'm not sure if I consider this a bug or not, but it's definitely not optimal behavior.

Lukas

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions