(Erlang语言)数据类型详细介绍——boxed对象
来源:互联网 发布:淘宝怎么改图片尺寸 编辑:程序博客网 时间:2024/06/10 00:06
Boxed 对象
Boxed 对象是比较复杂的对象,在 Erlang 中主标签为 10 的 Eterm 表示一个对 boxed 对象的引用。这个 Eterm 除去标签之后剩下的实际上是一个指针,指向具体的 boxed 对象。如下图所示,boxed 对象由对象头和具体的数据组成,这些字都排布在一起,占用进程栈中的一段连续空间(不像列表那样会分开)。
对象头分为 3 部分:主标签固定为 00(因此也没有 Eterm 以 00 为主标签),然后是 4 个位表示的 header 标签,这个标签表示了这个 boxed 对象的具体类型。接下来剩下的部分就是对象的大小 n,在对象头之后的 n 个字就是这个对象的具体数据。具体数据的格式和意义取决于具体的对象类型。对象头中表示大小的值也称为对象的 arity,目前在 Erlang 虚拟机中规定最多使用 24 位表示这个 n,因此对象最大不超过
224=16777215 个字。下面列出了 Erlang 虚拟机支持的所有 header 标签:
- 0000:表示元组,高位的 size 即元组中元素个数。
- 0001:内部使用的 binary 匹配状态。
- 001x:大数(bignum),x 为符号位,可以表示任意大的整数,限制取决于内存。
- 0100:本地 ref
- 0101:fun
- 0110:浮点数
- 0111:export 信息
- 1000:refc_binary,引用计数的 binary,即大 binary
- 1001:heap_binary,小 binary,直接放在堆中
- 1010:sub_binary,分离 binary 时产生的子 binary
- 1011:没有使用
- 1100:外部 pid
- 1101:外部 port
- 1110:外部 ref
- 1111:没有使用
以上这些 boxed 对象在 Erlang 虚拟机内都称为 thing。这些“东西”有一些是表示 Erlang 开发者可以直接使用的数据类型,有一些则表示内部数据类型。下面我们来依次了解这些数据类型。
元组
元组很简单,实际上就是一个数组,如下图所示的一个 3 元素的元组:
元组中的元素在内存中依次排开,中间没有间隔,每一个元素都是一个 Eterm,所以元组中的元素可以是任意类型的。和列表一样,如果创建一个元组的时候引用了其他对象,那么这些被引用的对象也是共享的。但是当元组跨越了进程的边界的时候,也会被扁平化。
大整数,浮点数
大整数的符号保存在对象头的标签中,因此大整数对象本身的数据保存的就是大整数的绝对值。由于 Erlang 支持任意大的整数,所以大整数的长度一定是至少 1 个字的。那么大整数是以什么样的格式保存在这些机器字中的呢?假设某个大整数需要用 n 个字表示,而且每一个机器字宽度为 64 位元,那么这个大整数的值为:
其中
浮点数就比较简单了。Erlang 中的浮点数是双精度浮点数,实际上就是编译器原生的 double 类型,因此在 64 位的机器上刚好是一个机器字的大小。那么浮点数对象的 header 很简单,除去固定标签之外,arity 值固定为 1。然后后面跟着的一个字大小的数据就是浮点数符合 IEEE 754 规范的表示形式(注4)。
本地 ref
如果是在 32 位机器上,ref 对象表示形式如下所示:
header 里面的 arity 总是设置为 3,后面跟着 3 个 32 位的机器字,其中第 0 个只用了 18 位。这个图也结解释了为什么 ref 的值超过了
在 64 位的机器上,ref 能表示的数据宽度也是 82 位,如果和 32 位机器不一样的话就不好交换数据了。那么如果在 64 位的机器上,只是简单地拓宽 header 以及后面的 3 个字,那么每个 ref 就要浪费
其中 word 0 依然只使用了 18 位,而且在 header 后面的第一个机器字的低 32 位还保存了一个数字 3,即后面跟着的 32 位元字数。
Erlang 虚拟机通过 3 个全局变量分别表示 word 0、1 和 2 的当前值。调用 BIF make_ref() 的时候,Erlang 虚拟机会创建一个新的 ref。由于全局当前 ref 值是用多个变量表示的,所以 make_ref() 会通过一个自旋锁保护对这些变量的操作,递增全局 ref 的值,然后根据新的 ref 值创建新的 ref 对象并返回对应的 Eterm。递增操作针对 word 0 递增,如果 word 0 超过了
我们打印 ref 的时候,得到的是类似 #Ref<0.0.0.2055> 这样的输出,通过 3 个句点将输出结果分为 4 段。第 1 段,和 pid 和 port 的第一段是一样的,表示节点,在本地节点总是为 0,后面 3 段分别为上面的 word 2、1 和 0。所以 ref 较少的时候前面几段都为 0。
binary
binary 的内容比较繁多,单独放在本系列的第 5 篇了。
外部 pid、port 和 ref
外部 Eterm 是 Erlang 虚拟机的分布式节点之间交换 Eterm 时所用的格式。由于具体涉及到分布式 Erlang 的工作细节,所以打算在专门介绍 Erlang 分布式机制的博文中具体讨论。
fun 和 export
涉及到 Beam 虚拟机的代码格式和工作原理,打算放在专门介绍 Beam 虚拟机的博文中具体讨论。
- (Erlang语言)数据类型详细介绍——boxed对象
- (Erlang语言)数据类型详细介绍——binary
- Erlang数据类型详细介绍(3)
- Erlang数据类型详细介绍(1)
- Erlang数据类型详细介绍(2)
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- C语言中time_t数据类型详细介绍
- [转] Erlang 语言介绍
- Erlang编程语言介绍
- Delphi数据类型详细介绍
- OpenCV学习笔记(五十六)——InputArray和OutputArray的那些事core
- 表单添加多个文件
- “秘密”社交挖握人性罪恶过多必死
- uiautomator中UiAutomatorBridge学习笔记(10)
- Unity3D 消息管理机制的实现
- (Erlang语言)数据类型详细介绍——boxed对象
- 设计模式(9)-结构型模式-Decorator模式
- 理解Javascript的闭包
- 详解Android中AsyncTask的使用
- c#:从DataTable中抽取Distinct数据
- 恢复SVN中删除的文件或文件夹
- Asterisk 1.4.0 CLI commands
- Sticks
- 自己动手写代码,整合Spring和Hibernate(三)之DAOSupport和DAOTemplate