Erlang 的process 是虚拟机层面的进程,每个Erlang process 都包括一个 pcb(process control block), 一个stack 以及私有heap .

这部分的姿势, 在各种论文中都有提到. 网上也有各种各样的解读,包括但不仅限于:

1, http://fengchj.com/?p=2255

2, http://blog.csdn.net/mycwq/article/details/26613275

那么, 从现有的资料,可以看出,正因为在Erlang 虚拟机内部,每个进程(process)都有自己的PCB,自己的stack和自己的私有heap(注意,现在的Erlang还不支持shared heap). Erlang的 GC 并不是"stop whe whole world",只是针对于每一个进程而言的.

Each process’ heap is garbage collected independently. Thus when one scheduler is collecting garbage for a process, other schedulers can keep executing other processes.

但是,并不是所有的数据都是private heap 的, 同样也有一些数据, 是存放在shared 区域的.

In addition, binaries larger than 64 bytes are stored in a common heap shared by all processes. ETS tables are also stored in a common heap.

binaries larger than 64 bytes, 也就是大家常说到的refc binaries, 这部分的解读网上也有很多, 举个栗子:

1, http://blog.csdn.net/zhongruixian/article/details/9450361

这个时候, Erlang的GC,就有可能遇到一些问题了,因为Erlang 虚拟机对待这部分shared memory 的GC,是采取引用计数器的.

然后,看一段完整的小程序:

 -module(refc_binary_test).

 -export ([start/0,
handle_big_binary/1]). start() ->
Me = erlang:self(),
erlang:spawn(?MODULE, handle_big_binary, [Me]),
receive
{ok, C} ->
io:format("----- get_bin_address C : ~p~n", [test:get_bin_address(C)]),
io:format("------- handled ~p~n", [erts_debug:get_internal_state({binary_info, C})]),
timer:sleep(1000000),
C;
_ ->
error
after 10000 ->
error
end. handle_big_binary(Me) ->
A = binary:copy(<<1>>, 1024*1024),
io:format("----- get_bin_address A : ~p~n", [test:get_bin_address(A)]),
io:format("------- resource ~p~n", [erts_debug:get_internal_state({binary_info, A})]),
<<B:1/binary, _/binary>> = A,
io:format("----- get_bin_address B : ~p~n", [test:get_bin_address(B)]),
erlang:send(Me, {ok, B}).

熟悉Ejabberd 的人,对这一模式应该不会陌生, handle_big_binary/1 的execute 进程可以映射到ejabberd 中的ejabberd_receiver module, start/0 可以看做是ejabberd 中的c2s 进程. ok, 和TCP socket 直接关联的进程会解析socket 数据, 解析完成后, 交给实际处理进程.

> refc_binary_test:start().
----- get_bin_address A : "bin: size=1048576, ptr=0x18fc0040"
------- resource {refc_binary,,{binary,},}
----- get_bin_address B : "bin: size=1, ptr=0x18fc0040"
----- get_bin_address C : "bin: size=1, ptr=0x18fc0040"
------- handled {refc_binary,,{binary,},}

那么, 这个时候, 可以看到 变量 C 还占据这'{binary,1048576}' 的数据(1048576 是binary 的orig_size),即便是handle_big_binary 的进程在send/2 之后就已经结束生命. 然后, 可以放大一下这个小问题:

> [proc_lib:spawn(refc_binary_test, start, []) || _ <- lists:seq(, )].

然后就会看到, beam.smp 进程已经占用了超过了1G的内存:(.

那,how fix ?

在binary module 中,referenced_byte_size/1 func:

If a binary references a larger binary (often described as being a sub-binary), it can be useful to get the size of the actual referenced binary. This function can be used in a program to trigger the use of copy/1. By copying a binary, one might dereference the original, possibly large, binary which a smaller binary is a reference to.

 store(Binary, GBSet) ->
NewBin =
case binary:referenced_byte_size(Binary) of
Large when Large > 2 * byte_size(Binary) ->
binary:copy(Binary);
_ ->
Binary
end,
gb_sets:insert(NewBin,GBSet).

然后, 在看binary:copy/1 的function 描述:

This function will always create a new binary, even if N = 1. By using copy/1 on a binary referencing a larger binary, one might free up the larger binary for garbage collection.

这个时候再去refc_binary_test:start(). 就不会出现上面的问题了.

总结:

1, refc binary 的存储使用的是shared memory;

2, 对于refc binary 的GC 策略是引用计数器;

3, refc binary 的内存分配是连续的.

Erlang process structure -- refc binary的更多相关文章

  1. a simple erlang process pool analysis

    a simple erlang process pool analysis 这是一个简单的erlang进程池分析,是learn you some erlang for Great Good 里面的一个 ...

  2. Erlang Process input queue

    http://www.cnblogs.com/me-sa/archive/2011/11/05/erlang0012.html Erlang进程有自己的消息队列来保存接收到的消息,新接收到的消息放在队 ...

  3. 【oracle学习笔记02】Oracle Architecture —— Process Structure

    Oracle中有三类进程: 1 User Process 2 Server Process Server Process is a program that directly interacts wi ...

  4. Erlang库 -- 有意思的库汇总

    抄自这里 首先,库存在的目的大致可分为:1.提供便利2.尽可能解决一些痛点 首先,我们先明确一下Erlang编程语言的一些痛点(伪痛点):1,单进程问题Erlang虚拟机属于抢占式调度,抢占式调度有很 ...

  5. Erlang数据类型的表示和实现(5)——binary

    binary 是 Erlang 中一个具有特色的数据结构,用于处理大块的“原始的”字节块.如果没有 binary 这种数据类型,在 Erlang 中处理字节流的话可能还需要像列表或元组这样的数据结构. ...

  6. Erlang 虚拟机内的内存管理(Lukas Larsson演讲听写稿)

    Erlang核心开发者Lukas Larsson在2014年3月份Erlang Factory上的一个演讲详细介绍了Erlang内存体系的原理以及调优案例: http://www.erlang-fac ...

  7. erlang二进制

    在Erlang中写处理二进制数据的代码是洋溢着幸福感的,它对于二进制强大的表现力甚至能让你忘掉了它种种不便,今天我们说说Erlang的二进制数据处理. Erlang中bit string代表无类型的内 ...

  8. 转载:【原译】Erlang构建和匹配二进制数据(Efficiency Guide)

    转自:http://www.cnblogs.com/futuredo/archive/2012/10/19/2727204.html Constructing and matching binarie ...

  9. erlang二进制数据垃圾回收机制

    erlang二进制数据在内存中有两种存在形式,当数据大小不到 64 bytes,就直接存在进程堆内.假设超过了64 bytes.就被保存到进程外的共享堆里,能够给节点内全部进程共享. erlang有两 ...

随机推荐

  1. python中模块导入问题(已解决)

    想在python中导入request包: 无此模块,于是先安装requests包: 但是提示"Requirement already satisfied".在提示的相应目录里,找到 ...

  2. 【eclipse】查看jar乱码问题解决

  3. (转载)Ubuntu 16.04+1080Ti机器学习基本环境配置

    转载自:https://blog.csdn.net/mahonesun/article/details/80808930 一.设置网络 机器有两张网卡,将当前正在使用的"有线连接1" ...

  4. 使用 while 循环

    与 for 循环不同,while 循环会一直运行,直到给定条件不满足为止.例如,下面的 while 循环从 x=0 开始.每次循环都会检查 x<=10 是否成立.如果成立,就执行循环内部的表达式 ...

  5. BeginInit与EndInit的实践总结

    在项目中,遇到这种情况,总结随便如下: 初始化时:添加操作,BeginInit{flag=true}  警情是一条条加入的,全部都加入后,图表再一次性生成   EndInit{flag=false} ...

  6. Tornado源码分析 --- Redirect重定向

    “重定向”简单介绍: “重定向”指的是HTTP重定向,是HTTP协议的一种机制.当client向server发送一个请求,要求获取一个资源时,在server接收到这个请求后发现请求的这个资源实际存放在 ...

  7. Appium 自动化测试(3)--Appium框架与流程介绍

    Appium介绍 Appium是一个移动端的自动化框架,可用于测试原生应用,移动网页应用和混合型应用,且是跨平台的.可用于IOS和Android以及firefox的操作系统.原生的应用是指用andro ...

  8. 移动APP测试要点总结

    ***微信扫一扫,关注“python测试开发圈”,了解更多测试教程!***

  9. C++常考面试题

    1 new/delete 与 malloc/free的区别 运算符是语言自身的特性,有固定的语义,编译器知道意味着什么,由编译器解释语义,生成相应的代码. 库函数是依赖于库的,一定程度上独立于语言的. ...

  10. Python3 字符串(七)

    字符串是 Python 中最常用的数据类型.我们可以使用引号( ' 或 " )来创建字符串. 创建字符串很简单,只要为变量分配一个值即可. python中单引号和双引号使用完全相同. 使用三 ...