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_to_term 函数,用于把二进制数据转为原始的erlang数据。这个函数都是c实现的,这里用erlang语言实现了,很有参考价值,其他语言可以参考这个解析erlang二进制协议数据。配套文章地址...
在Erlang里面,Binary支持强大的模式匹配,这为编写网络通讯程序提供了便利。但是关于 bit syntax 语法来说,理解还是不太容易。 借此文档,希望给大家有帮助。
Erlang OTP 20.1 Windows 64-bit Binary File 下载地址:http://www.erlang.org/downloads
NULL 博文链接:https://ZacMa.iteye.com/blog/1976833
学习RabbitMQ 需要安装Erlang语言,作为运行环境,而官网是国外资源,下载速度过慢。所以放上Erlang 22.2 供大家学习使用
有些同学想把Erlang数据通过term_to_binary函数封包后以二制进形式存入数据库,然后用PHP读取并解包成PHP数组。 为了解决上面的这种应用场合中遇到的问题, 参考peb(Php-Erlang Bridge)扩展写了这个类似erlang:...
get the most speed out of binary pattern matching are no longer necessary. In fact, the ugly code is slower than the clean code (because the clean code has become faster, not because the uglier code ...
In 2014, the author, Wolfgang Loder, developed a repository for digital assets that had to deliver those assets in binary form quickly and reliably, being able to deal with at least hundreds of ...
OTP 22.0 64 位安装包 Windows下 64-bit Binary File
clojure-erlastic:Micro库,它使用erlang JInterface库来解码和编码Binary Erlang Term和带有core.async通道的简单erlang端口接口。 因此,您可以使用clojure抽象与erlang协程进行通信
它是erlang:binary的包装,以及一些类似String的函数。 当使用它而不是erlang的:binary时,您会获得更多性感的代码和类型规范,此外,您还将获得String提供的一些功能,例如reverse/1 , trim_trailing/2等。您...
binary_tools是Erlang二进制数据类型的一组辅助服务函数。 目录树 $ tree . ├── README.md ├── c_src │ └── binary_tools.c ├── ebin ├── example │ └── get_bin_address_ex.erl ├── ...
用于在Erlang中重播日志的磁盘队列 特征 队列项目被写入磁盘上的段文件中,以便在重启后不受影响。 批量弹出项目超出了大小/计数限制的队列。 提供ack/2 API来记录读取器在段中的位置。 添加配置选项max_total_...
Start tracer -> Start program -> Stop trace -> Analyze trace binary -> Draw graph 用法 为了简单使用,请编译tracer.erl并与您的程序一起将tracer.beam添加到Erlang的代码加载路径中。 并指定要跟踪和跟踪模式...
埃格金 egherkin是用于解析Gherkin文档的Erlang库。 目标 egherkin旨在以较小的代码库提供完整的...egherkin:parse(Document :: binary()) -> ParseResult egherkin:parse_file(Filename :: string()) -> Pars
简而言之,将功能添加到src中新的或现有的erlang模块中。 函数名称必须以horse_开头,以便horse测试运行程序使用。 如果horse:repeat/2出现在函数中,例如: horse_perf_test () -> horse : repeat ( 100 , ...
binpp::1234:Erlang二进制漂亮打印机
欧姆卫士解析转换my_func(X) when is_binary(X) ... ohmyguard支持所有 erlang 类型: omg_atom ( X / atom ) -> X .omg_binary ( X / binary ) -> X .omg_bitstring ( X / bitstring ) -> X .omg_float ( X / float )
memory database, Er- lang ETS, using a relatively-new data structure, called a Judy array, was studied by comparing the performance of ETS tables based on four data structures: AVL balanced binary ...
在以下情况下,您可以直接从GET Web服务以精美的方式直接查看BERT数据(erlang项的二进制表示):-响应主体为原始二进制erlang项,内容类型为“ application / x-erlang-binary”-响应主体是base64编码的二进制...