走向erlang基层
balalanl7
erlang开发欢迎加 main_argc 探讨交流,备注:csdn
展开
-
erlang sets 性能分析
有个业务需要大量存取增删非重复数据,原实现逻辑是使用set的数据结构。set结构本质上是用erlang实现的,对数据哈希后结合tuple和list的一层包装,set出生在erlang还没有maps结构时的早期版本,用以比单独的list结构更高效的解决集合问题。maps结构出现后,能否高效的替代掉set呢?下面做一些对比:增操作:时间消耗差了一个数量级查操作:删操作:耗时方面,maps全面碾压set。但maps也有缺点,在空间占用上:maps方式占用空间略大的原因是多存储了null这个值原创 2022-05-27 11:36:05 · 351 阅读 · 2 评论 -
erlang ets源码实现浅析
新建ets时默认配置为:[set, protected, {keypos,1}, {heir,none}, {write_concurrency,false}, {read_concurrency,false}, {decentralized_counters,false}]先看ets:new时会发生什么,即源码 erl_db.c 中 ets_new_2 函数核心实现为:DbTable* tb = NULL; //ets表底层存储数据的结构meth = &db_hash; //注, 设原创 2021-08-28 23:00:07 · 803 阅读 · 0 评论 -
erlang on_heap off_heap 源码剖析
进行消息发送时主要有以下过程:1.计算消息大小2.分配能容纳整个消息的空间3.复制消息负载4.分配消息容器的元数据5.在接收者进程的消息队列中插入消息容器接收方进程的message_queue_data进程标志控制着步骤2中发送方消息的分配策略以及决定了后续垃圾回收时如何处理消息数据。我们可以使用 process_flag(message_queue_data, off_heap | on_heap) 为每个进程配置不同的消息占用空间的行为,或者可以在启动时使用选项 +hmqd 为所有进程进行原创 2021-07-30 11:41:17 · 368 阅读 · 0 评论 -
erlang 热更卡死之谜
案发现场:想让一业务繁忙的进程多被调度,于是在该进程启动时调用process_flag(priority, high)提高进程优先级。之后便出现热更卡死的情况。刑侦知识:热更部分:当我们使用c(被热更模块名),进行热更时,实际上是把热更任务丢给了系统启动的名为erts_code_purger的进程。erts_code_purger.erl中找到do_soft_purge的函数实现,有如下调用 {PurgeOp, NewReqs} = check_proc_code(erlang:processes原创 2021-04-29 11:33:54 · 558 阅读 · 0 评论 -
erlang gc模拟器——直观理解gc规则
-module(gc_simulation).-compile(export_all).-record(memory_data, { heap_stack = 0, heap = 0, stack = 0, high_water = 0, old_heap = 0, old_heap_max = 0, %% 标记过期数据 heap_garbage = 0}).heap_size() -> ListA = lists:foldl(fun(_, [H1, H2|Acc])原创 2021-04-15 17:13:51 · 1311 阅读 · 0 评论 -
erlang尾递归更快么?
我们先看两段递归实现:尾递归和其对应的汇编码:tail_rec(_, [], Acc) -> lists:reverse(Acc); tail_rec(F, [H|T], Acc) -> tail_rec(F, T, [F(H)|Acc]). //注:虽然 beam_emu.c 中有 #define y(N) E[N]。 E[0]为进程空间的栈顶 //但是加载器在加载到 {y,Y}时,会将Y加1。也就是说我们看汇编码中的Y(N),实际对应的地址为E[N+1] {label,4}.原创 2021-04-13 14:41:08 · 858 阅读 · 0 评论 -
erlang catch和try 底层实现剖析
跟try有关的外部通用指令有四条,分别是{"try", 2, -1, 0, 7521}, //特定指令id为-1,指令转换操作的地址偏移为7521{"try_end", 1, 461, 1, -1}, //对应特定指令id为461 {"try_case", 1, 459, 1, -1}, //对应特定指令id为459 {"try_case_end", 1, 460, 1, -1}, //对应特定指令id为460我们发现try指令对应的特定指令为-1,也就是说try指令不是直接转换为特殊指令的,而是原创 2021-04-08 14:33:56 · 1139 阅读 · 0 评论 -
erlang编译系列之流程概括
我们从compile:file/1函数入手,先梳理下编译的流程。下面是抽丝剥茧后一些核心的代码:file(File) -> file(File, [verbose,report_errors,report_warnings]). //file会调用到internal({file,File}, Opts) -> {Ext,Ps} = passes(file, Opts), // 一些列的操作列表 Compile = #compile{options=Opts,mod_optio原创 2021-03-25 00:13:04 · 1173 阅读 · 0 评论 -
Erlang进程字典底层实现剖析
进程字典的结构:typedef struct proc_dict { unsigned int sizeMask; // 掩码,用于计算hash值落到data的索引值 unsigned int usedSlots; // 可以使用的插槽数(不等于已经被使用的插槽数) unsigned int arraySize; // data数组的长度 unsigned int splitPosition; Uint numElements; //原创 2021-01-13 16:04:43 · 1406 阅读 · 0 评论 -
Erlang数据类型底层实现剖析 三
这回我们看 hashmap_from_validated_list(BIF_P, BIF_ARG_1, size)的实现static Eterm hashmap_from_validated_list(Process *p, Eterm list, Uint size) { while(is_list(item)) { res = CAR(list_val(item)); kv = tuple_val(res); hx = hashmap_res原创 2020-12-15 17:40:58 · 1147 阅读 · 0 评论 -
Erlang数据类型底层实现剖析 二
tuple实现:我们从erlang:make_tuple/2的底层实现来看看tuple的组织:erlang:make_tuple(4, []).{[],[],[],[]}BIF_RETTYPE make_tuple_2(BIF_ALIST_2){ Sint n; Eterm* hp; Eterm res; if (is_not_small(BIF_ARG_1) || (n = signed_val(BIF_ARG_1)) < 0 || n > ERT原创 2020-11-06 17:39:42 · 1046 阅读 · 0 评论 -
Erlang数据类型底层实现剖析 一
Erlang中所有数据类型,在Erlang虚拟机中都是通过64位的(默认大家都是64位的操作系统)名为Eterm的数值组合(一个或多个Eterm)构成的。虚拟机会使用Eterm的某几位来标记这个Eterm是什么类型(这几位又叫标签,Tag),再根据Tag的不同,对Eterm进行不同的解释。下面列出所有Tag的定义,并进行简单的注解#define _TAG_PRIMARY_SIZE 2 一等Tag的位数 注:Tag有分等级,一等Tag有四类#define _TAG_PRIMARY_MASK原创 2020-08-18 14:30:57 · 1350 阅读 · 0 评论 -
erlang garbage_collect 源码剖析
两个词可以概括整个gc流程:分代:数据存储区域分为年轻堆(the young heap)和年老堆(the oldheap),年轻堆的数据在经历过两轮小回收后还存活的话,会被转移到年老堆。复制:gc时会计算新堆的大小并重新申请空间,将旧堆存活数据复制到新堆回收类型:小回收(minor_collection):只对年轻堆进行垃圾回收大回收(major_collection):年轻堆和年老堆都进行垃圾回收首先我们来看erl的进程结构(erlang_process.h)中,关于内存管理的一些字原创 2020-08-13 15:31:09 · 3320 阅读 · 0 评论 -
erlang send_after 源码剖析
概念简介:tick最小单位为1毫秒每个调度进程有自己的时间轮–(soon轮 later轮)soon轮 早轮早轮的每个槽宽度为1个tick,一共有2的14次方个槽。存储大约16秒内需要被触发的定时器later轮 晚轮晚轮的每个槽宽度为2的13次方个tick,一共有2的14次方个槽。存储大约37个小时内需要被触发的定时器超过晚轮的定时器,怎么处理?超过晚轮的定时器,暂且称为高级定时器; 没有超过晚轮的定时器,暂且称为普通定时器。高级定时器信息存于ErtsSchedulerData 的timer原创 2020-07-23 16:14:13 · 1733 阅读 · 0 评论