1. binary数据是可以在不同进程间共享的
当然这些进程都在同一Erlang节点上。
这与普通term不同,后者作为消息在进程间传递时是要在接收进程中做拷贝的(当然atom数据例外,它们也不会做拷贝)。摘一段
原文在这里:
All data in messages between Erlang processes is copied, with the exception of
refc binaries on the same Erlang node.
bintest是一个察看binary内存地址的小程序(附后),用它验证一下:
1> Bin = <<1,2,3,4,5,6,7,8>>.
<<1,2,3,4,5,6,7,8>>
2> bintest:get_bin_address(B).
"bin: size=8, ptr=0x7ff2e131bc03"
3> P = spawn(fun() -> receive BinMsg -> BinInfo = bintest:get_bin_address(BinMsg), io:format("~s~n", [BinInfo]) end end).
4> P ! B.
bin: size=8, ptr=0x7ff2e131bc03
<<1,2,3,4,5,6,7,8>>
binary在进程间共享带来的问题就是
垃圾回收时的麻烦,(可以用引用计数的方式处理?),这是erlang虚拟机实现者的麻烦,有时候也给我们应用开发者带来麻烦。
2. 模式匹配得到的binary,实际上是匹配目标字节流的一个片断(sub-binary)
1> Bin = <<1,2,3,4,5,6,7,8>>.
<<1,2,3,4,5,6,7,8>>
2> <<_:3/binary, B:3/binary, _/binary>> = Bin.
<<1,2,3,4,5,6,7,8>>
3> B.
<<4,5,6>>
4> binary:referenced_byte_size(Bin).
8
5> binary:referenced_byte_size(B).
8
我们可能有一个很大的Bin,然后对它进行匹配查找,找到其中一小段B,实际上这两个变量都指向同一个binary(的不同位置和大小)。可以通过binary:referenced_byte_size/1函数察看变量引用背后的二进制数据的实际大小,如上面例子所示。所以除非这两个变量都释放,它们实际引用的那个大binary就不会被垃圾回收。
binary:referenced_byte_size/1得到binary变量所引用的原始binary数据的大小。所以模式匹配出来的binary变量还是引用到了原始的数据,没有任何拷贝操作。可以进一步看看binary变量引用的字节流地址:
6> bintest:get_bin_address(Bin).
"bin: size=8, ptr=0x7f9556578c00"
7> bintest:get_bin_address(B).
"bin: size=3, ptr=0x7f9556578c03"
8> C = binary:copy(B).
<<4,5,6>>
9> niftest:get_bin_address(C).
"bin: size=3, ptr=0x7f9556239f78"
有可能出现这种情况:在查找完后原来那个大binary不再有用,有用的是那些查找到的结果,这种情况下那个大binary占着大块内存又用不着,由于有小对象引用都指向它,所以也无法垃圾回收。浪费内存实在可耻。这种情况可以考虑使用binary模块的copy函数,我们用binary:copy/1把那些找到的每个小binary都拷贝一份出来,这样就不再引用到原来的大binary对象了,没有引用的binary就可以被垃圾回收了。
3. binary与字符串
在erlang中,binary也用做高效的string,但是上述内存共享办法会给nif之间binary字符串的传递带来问题。要处理的字符串可能来自于一个大binary中的一个片段,我们是无法直接将它作为C语言的字符串处理的,因为C字符串需要一个\0作为字符串的结尾。好在我们知道这个字符串的长度。通过复制添\0的方式可以转换成C能处理的字符串。
这本质上是两种语言内部对binary字符串的表达方式的不同造成的麻烦:一种以\0标志字符串,另一种以长度。
enif_make_string_len可用来处理非\0的C字符串给elang,只要知道长度就行。这其实是erlang的binary字符串处理方式了,这样没有\0结尾的binary字符串也能当成成字符串给erlang用了。
而enif_make_sub_binary是用来在C中模仿erlang的字符串binary操作的。
enif_get_string将erlang字符串(实际上是list,跟binary无关了)转换成\0结尾的C字符串。
而enif_inspect_iolist_as_binary,则是将一个iolist的erlang字符串转换成一个erlang的binary字符串
enif_inspect_iolist_as_binary使用的陷阱是要注意binary字符串是以长度而不是\0标识的。在C中使用使要做转换:
ErlNifBinary tilefilenameBin;
if (!enif_inspect_iolist_as_binary(env, argv[1], &tilefilenameBin) || (tilefilenameBin.size >= 64)) {
return enif_make_badarg(env);
}
char tilefilename[64] = "";
memcpy(tilefilename, tilefilenameBin.data, tilefilenameBin.size);
附
bintest是一个察看binary内存地址的小程序,利用了
nif的ErlNifBinary结构:
typedef struct {
unsigned size;
unsigned char* data;
} ErlNifBinary;
-module(bintest).
-export([get_bin_address/1]).
-on_load(init/0).
init() ->
erlang:load_nif("./bintest", 0).
get_bin_address(_Bin) ->
erlang:error({"NIF not implemented in nif_test at line", ?LINE}).
对应的nif C:
#include "erl_nif.h"
#include <stdio.h>
static ERL_NIF_TERM get_bin_address(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ErlNifBinary bin;
enif_inspect_binary(env, argv[0], &bin);
char buf[256];
sprintf(buf, "bin: size=%zu, ptr=%p", bin.size, bin.data);
return enif_make_string(env, buf, ERL_NIF_LATIN1);
}
static ErlNifFunc nif_funcs[] =
{
{"get_bin_address", 1, get_bin_address}
};
ERL_NIF_INIT(bintest,nif_funcs,NULL,NULL,NULL,NULL);
linux下的编译命令:
gcc -std=c99 -fPIC -shared -o bintest.so bintest.c -I/usr/local/lib/erlang/usr/include
分享到:
相关推荐
### Erlang Binary与Bit String 数据类型详解 #### 引言 Erlang 是一种功能强大且灵活的编程语言,尤其适合开发高并发、分布式及容错性应用。自 R12B 版本以来,Erlang 在处理二进制数据方面引入了两项重大更新:...
erlang提供了binary_to_term 函数,用于把二进制数据转为原始的erlang数据。这个函数都是c实现的,这里用erlang语言实现了,很有参考价值,其他语言可以参考这个解析erlang二进制协议数据。配套文章地址...
Erlang OTP 20.1 Windows 64-bit Binary File 下载地址:http://www.erlang.org/downloads
标题中的“<27>erlang record”可能指的是Erlang编程语言中的Record特性,它是一种数据结构,类似于结构体或者哈希表,用于组织和操作数据。在Erlang中,Record提供了一种方便的方式来定义和访问具有固定字段的数据...
### 关于Erlang OTP系统文档的关键知识点 #### 标题与描述概述 - **标题**:“Erlang User Reference Manual”(Erlang 用户参考手册) - **描述**:“Erlang OTP官方用户手册 开发指南” 这些信息表明本手册是...
Erlang是一种高级编程语言,特别为并发、分布式和实时系统设计,由瑞典电信设备制造商Ericsson开发。在IT行业中,Erlang因其强大的错误恢复能力和热代码升级特性而受到欢迎,尤其在大规模并发系统、网络应用以及消息...
readers可以从Erlang官方网站下载最新的Windows binary版本。安装Erlang OTP非常简单,只需要按照安装程序的提示进行操作。 二、安装Emacs W32 Emacs W32是Windows平台下的Emacs版本,提供了功能强大且高度可定制...
- **高效数据结构**:Erlang内置了几种高效的数据类型如原子(Atom)、二进制(Binary)、列表(List)和元组(Tuple)。 - **垃圾收集**:ERTS采用了标记-清除算法,并支持分代垃圾回收策略。 - **软实时系统**:ERTS支持软...
有些同学想把Erlang数据通过term_to_binary函数封包后以二制进形式存入数据库,然后用PHP读取并解包成PHP数组。 为了解决上面的这种应用场合中遇到的问题, 参考peb(Php-Erlang Bridge)扩展写了这个类似erlang:...
本效率指南无法教会您如何编写高效代码,但可以提供一些关于避免哪些做法以及应该使用哪些特性的建议,并帮助您了解某些语言特性是如何实现的。通常,我们没有包括适用于所有语言的一般优化技巧,例如将循环中的常见...
Erlang 提供了强大的并行处理能力,它的 BEAM(Binary Emulation of a Machine)虚拟机支持轻量级进程和热代码替换,确保了系统在运行时可以无缝升级。这个版本的 Erlang 支持 RabbitMQ 3.8.x 系列,为 RabbitMQ ...
1. **二进制处理**:使用Erlang的`binary`模块,如`binary:match/3`和`binary:split/3`,直接在二进制数据上进行查找和分割,避免了转换成其他数据结构的开销。 2. **流式解析**(Streaming Parsing):为了避免一...
- **MaxMind GeoLiteCity Binary DB**:用于存储IP地理位置数据。 - **EGeoIP**:一个用于访问MaxMind数据库的Erlang客户端库。 #### 三、开发流程与关键技术 ##### 1. OTP简介 OTP (Open Telecom Platform) 是...
13. **erlang**: 基础函数,如`length/1`获取列表长度,`element/2`访问元组元素,`binary_to_list/1`二进制转列表。 14. **binary**: 处理二进制数据的函数,如`bin_to_list/1`和`list_to_bin/1`之间的转换。 ...
- **IP数据库**: MaxMind GeoLiteCity Binary DB - **客户端库**: egeoip (用于访问MaxMind数据库) #### 三、项目结构与配置 - **项目目录结构**: - `srv`: 存放Erlang源代码文件。 - `ebin`: 编译后的Erlang目标...
otp_win64_22.1的官方地址下载太慢,共享一下otp_Erlang_win64_22.1百度云下载地址
6. **数据结构与模式匹配**:Erlang的元组(tuple)、列表(list)和二进制数据(binary)等数据结构在源码中会得到广泛运用。模式匹配用于解构数据和条件分支,使得代码更简洁。 7. **网络编程**:OpenPoker作为...
### Erlang分布式调用与TableServer支持详解 #### 前言 Erlang作为一种专为构建高并发、高可用性系统而设计的编程语言,其核心特性之一就是强大的分布式处理能力。本篇文档旨在深入解析Erlang的分布式调用机制及...
Clojure-erlastic是一个微小但功能强大的库,旨在为Clojure开发者提供一个简单而高效的接口,以利用Erlang的JInterface库来处理Binary Erlang Term(BERT)的编码和解码,并通过core.async通道与Erlang进程进行通信...