引自:http://cryolite.iteye.com/blog/1547252

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. 1> Bin = <<1,2,3,4,5,6,7,8>>.
  2. <<1,2,3,4,5,6,7,8>>
  3. 2> bintest:get_bin_address(B).
  4. "bin: size=8, ptr=0x7ff2e131bc03"
  5. 3> P = spawn(fun() -> receive BinMsg -> BinInfo = bintest:get_bin_address(BinMsg), io:format("~s~n", [BinInfo]) end end).
  6. 4> P ! B.
  7. bin: size=8, ptr=0x7ff2e131bc03
  8. <<1,2,3,4,5,6,7,8>>

binary在进程间共享带来的问题就是垃圾回收时的麻烦,(可以用引用计数的方式处理?),这是erlang虚拟机实现者的麻烦,有时候也给我们应用开发者带来麻烦。

2. 模式匹配得到的binary,实际上是匹配目标字节流的一个片断(sub-binary)

  1. 1> Bin = <<1,2,3,4,5,6,7,8>>.
  2. <<1,2,3,4,5,6,7,8>>
  3. 2> <<_:3/binary, B:3/binary, _/binary>> = Bin.
  4. <<1,2,3,4,5,6,7,8>>
  5. 3> B.
  6. <<4,5,6>>
  7. 4> binary:referenced_byte_size(Bin).
  8. 8
  9. 5> binary:referenced_byte_size(B).
  10. 8

我们可能有一个很大的Bin,然后对它进行匹配查找,找到其中一小段B,实际上这两个变量都指向同一个binary(的不同位置和大小)。可以通
过binary:referenced_byte_size/1函数察看变量引用背后的二进制数据的实际大小,如上面例子所示。所以除非这两个变量都释
放,它们实际引用的那个大binary就不会被垃圾回收。

binary:referenced_byte_size/1得到binary变量所引用的原始binary数据的大小。所以模式匹配出来的binary变量还是引用到了原始的数据,没有任何拷贝操作。可以进一步看看binary变量引用的字节流地址:

  1. 6> bintest:get_bin_address(Bin).
  2. "bin: size=8, ptr=0x7f9556578c00"
  3. 7> bintest:get_bin_address(B).
  4. "bin: size=3, ptr=0x7f9556578c03"
  5. 8> C = binary:copy(B).
  6. <<4,5,6>>
  7. 9> niftest:get_bin_address(C).
  8. "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中使用使要做转换:

  1. ErlNifBinary tilefilenameBin;
  2. if (!enif_inspect_iolist_as_binary(env, argv[1], &tilefilenameBin) || (tilefilenameBin.size >= 64)) {
  3. return enif_make_badarg(env);
  4. }
  5. char tilefilename[64] = "";
  6. memcpy(tilefilename, tilefilenameBin.data, tilefilenameBin.size);

bintest是一个察看binary内存地址的小程序,利用了nif的ErlNifBinary结构

  1. typedef struct {
  2. unsigned size;
  3. unsigned char* data;
  4. } ErlNifBinary;
  1. -module(bintest).
  2. -export([get_bin_address/1]).
  3. -on_load(init/0).
  4. init() ->
  5. erlang:load_nif("./bintest", 0).
  6. get_bin_address(_Bin) ->
  7. erlang:error({"NIF not implemented in nif_test at line", ?LINE}).

对应的nif C:

  1. #include "erl_nif.h"
  2. #include <stdio.h>
  3. static ERL_NIF_TERM get_bin_address(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  4. ErlNifBinary bin;
  5. enif_inspect_binary(env, argv[0], &bin);
  6. char buf[256];
  7. sprintf(buf, "bin: size=%zu, ptr=%p", bin.size, bin.data);
  8. return enif_make_string(env, buf, ERL_NIF_LATIN1);
  9. }
  10. static ErlNifFunc nif_funcs[] =
  11. {
  12. {"get_bin_address", 1, get_bin_address}
  13. };
  14. ERL_NIF_INIT(bintest,nif_funcs,NULL,NULL,NULL,NULL);

linux下的编译命令:

    1. gcc -std=c99 -fPIC -shared -o bintest.so bintest.c -I/usr/local/lib/erlang/usr/include

关于erlang的binary的更多相关文章

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

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

  2. Erlang第二课 ---- bit串

    Erlang是被设计来用在电信设备中的,这意味着需要处理大量的二进制数据.也正因为如此,Erlang把binary和binary string提升到了一个相当高的位置,提供了极为丰富的操作机制.当然, ...

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

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

  4. Erlang/Elixir: 使用 OpenCV, Python 搭建图片缩略图服务器

    这篇文章是在OSX上测试和运行的的, Ubuntu下的安装和配置请移步到这里 应用程序进程树, 默认 Poolboy 中初始化10个用于处理图片的 Python 工作进程(Worker) 首先安装Op ...

  5. Archive for the ‘Erlang’ Category 《Erlang编程指南》读后感

    http://timyang.net/category/erlang/ 在云时代,我们需要有更好的能利用多核功能及分布式能力的编程语言,Erlang在这方面具有天生的优势,因此我们始终对它保持强烈关注 ...

  6. windows安装rabbitmq

    官网下载windows安装版本:http://www.rabbitmq.com/install-windows.html ,安装文件rabbitmq-server-3.6.5.exe 前提:安装erl ...

  7. C# 消息队列

    阅读目录 1. 消息队列是什么? 2. 常见的消息队列框架有哪些? 3. MSMQ介绍 4. RabbitMQ介绍 消息队列是什么 简单的理解就是将消息添加一个队列中,使用时在从这个队列中取出来.那么 ...

  8. windows下安装RabbitMq-Service

    一.RaibbitMQ服务器配置 1. 准备工作.如果之前安装过RabbitMQ软件,若想重新安装,必须先把之前的RabbitMQ相关软件卸载. 2. 安装ERLANG语言包.首先到http://ww ...

  9. RabbitMQ安装和配置

    RabbitMQ: MQ:message queue.MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来 ...

随机推荐

  1. 一点公益二码公益开发模式系统源码App

    写这篇文章,是因为最近看到的一个著名的开源项目在内部使用时的各种问题,不得不说,很多的开源的东西思想是不错的,但离真正工程化都有不小的距离,所以没什么商业公司采用的开源产品如果要引入的话一定要慎重,通 ...

  2. Linux软件安装管理 - CentOS

    ---恢复内容开始--- 1. 软件包管理简介 1.1 源码包 - 脚本安装包 1.2 二进制包(RPM包,系统默认包) - 依赖性 2. rpm命令管理(Redhat Package Manager ...

  3. Xcode使用小结2

    刷新时间慢的时候用timer定时器 以下内容为借用,作者:FlyElephant出处:http://www.cnblogs.com/xiaofeixiang iOS开发-NSOperation与GCD ...

  4. 【APP测试初体验】android测试命令----adb常用命令

    --adb shell 命令adb devices 查看设备adb shell adb shell "ls -al /system/bin" >e:\a.txtsample_ ...

  5. Java基础之异常

    1.异常的概念 异常:程序在运行时出现的不正常情况,也可以说是出现的问题: Java中的异常:出现的不正常的问题也是一类事物,这类事物有一些共性的东西,比如有名称,有产生的原因等,将这些共性的部分抽取 ...

  6. php的redis的pconnect

    1. 当使用pconnect时,连接会被重用,连接的生命周期是fpm进程的生命周期,而非一次php的执行. 2.如果代码中使用pconnect, close的作用仅是使当前php不能再进行redis请 ...

  7. ngrok内网穿透神器

    ngrok类似国内的花生壳,可以将本地的内网映射到公网上,这样就可以做web开发,微信开发了.下面就介绍下ngrok是怎么配置的吧. 方式一: 一.打开ngrok的官网https://ngrok.co ...

  8. HDU 4442 Physical Examination(贪心)

    HDU 4442 Physical Examination(贪心) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=4442 Descripti ...

  9. for clean

    static(修饰变量方,法:静态块:静态内部类:静态导包) final transient 作用foreach 原理 volatile底层原理实现 集合LIST MAP SET 实现类的底层原理优, ...

  10. Linux Date命令学习笔记

    date 根据给定格式显示日期或设置系统日期时间.print or set the system date and time 指令所在路径:/bin/date 命令参数: 参数 描述 -d 显示字符串 ...