11  高级

11 高级

高效编程的良好开端是了解不同的数据类型和操作需要多少内存。Erlang 数据类型和其他项占用多少内存取决于实现,但下表显示了 OTP 19.0 中 erts-8.0 系统的一些数据。

度量单位是内存字。存在 32 位和 64 位实现。因此,一个字分别为 4 字节或 8 字节。运行系统的值可以通过调用 erlang:system_info(wordsize) 来确定。

数据类型 内存大小
小整数 1 个字。
在 32 位架构上:-134217729 < i < 134217728(28 位)。
在 64 位架构上:-576460752303423489 < i < 576460752303423488(60 位)。
大整数 3..N 个字。
原子 1 个字。
原子引用原子表,原子表也占用内存。原子文本在该表中对每个唯一原子存储一次。原子表 **不会** 被垃圾回收。
浮点数 在 32 位架构上:4 个字。
在 64 位架构上:3 个字。
二进制 3..6 个字 + 数据(可以共享)。
列表 1 个字 + 每个元素 1 个字 + 每个元素的大小。
字符串(与整数列表相同) 1 个字 + 每个字符 2 个字。
元组 2 个字 + 每个元素的大小。
小映射 5 个字 + 所有键和值的大小。
大映射(> 32 个键) N x F 个字 + 所有键和值的大小。
N 是映射中的键数量。
F 是一个稀疏因子,由于内部 HAMT 数据结构的概率性质,它可以在 1.6 和 1.8 之间变化。
Pid 当前本地节点的进程标识符 1 个字。
在 32 位上:另一个节点的进程标识符 6 个字。
在 64 位上:另一个节点的进程标识符 5 个字。
进程标识符引用进程表和节点表,它们也占用内存。
端口 当前本地节点的端口标识符 1 个字。
另一个节点的端口标识符 5 个字。
端口标识符引用端口表和节点表,它们也占用内存。
引用 在 32 位架构上:当前本地节点的引用 4-7 个字,另一个节点的引用 7-9 个字。
在 64 位架构上:当前本地节点的引用 4-6 个字,另一个节点的引用 6-7 个字。
引用还引用更多或更少的模拟器内部数据结构,这些结构也占用内存。至少它引用节点表。
Fun 9..13 个字 + 环境的大小。
Fun 引用 Fun 表,Fun 表也占用内存。
Ets 表 最初 768 个字 + 每个元素的大小(6 个字 + Erlang 数据的大小)。表在需要时会增长。
Erlang 进程 生成时 338 个字,包括一个 233 个字的堆。

表 11.1:  不同数据类型的内存大小

Erlang 语言规范对进程数量、原子长度等没有限制。但是,出于性能和内存节省的原因,在 Erlang 语言和执行环境的实际实现中总是会存在限制。

进程 默认情况下,同时存在的 Erlang 进程的最大数量为 262,144。此限制可以在启动时配置。有关更多信息,请参见 ERTS 中 erl(1) 手册页中的 +P 命令行标志。
运行时系统实例上的唯一本地进程标识符 在 64 位系统上,最多可以创建 2⁶⁰ - 1 个唯一进程标识符,而在 32 位系统上,最多可以创建 2²⁸ - 1 个唯一进程标识符。
已知节点 如果节点 X 上存在来自 Y 的任何 pid、端口、引用或 fun(Erlang 数据类型),或者如果 X 和 Y 相连,则远程节点 Y 必须为节点 X 所知。单个节点同时/曾经知道的远程节点的最大数量受 可用于节点名称的原子数量的最大值 限制。除节点名称原子外,与远程节点相关的所有数据都会被垃圾回收。
连接的节点 同时连接的节点的最大数量受同时知道的远程节点的最大数量、可用(Erlang)端口的最大数量可用套接字的最大数量 的限制。
原子中的字符 255.
原子 默认情况下,原子的最大数量为 1,048,576。此限制可以使用 +t 选项提高或降低。
元组中的元素 元组中元素的最大数量为 16,777,215(24 位无符号整数)。
二进制的大小 在 Erlang 的 32 位实现中,536,870,911 字节是使用位语法可以构建或匹配的最大二进制文件。在 64 位实现中,最大大小为 2,305,843,009,213,693,951 字节。如果超出限制,则位语法构建将失败并出现 system_limit 异常,而任何尝试匹配过大的二进制文件都将失败。此限制从 R11B-4 开始实施。
在早期的 Erlang/OTP 版本中,对过大二进制文件的操作通常会失败或给出错误的结果。在将来的版本中,其他创建二进制文件的操作(例如 list_to_binary/1)也可能会强制执行相同的限制。
Erlang 节点分配的总数据量 Erlang 运行时系统可以使用完整的 32 位(或 64 位)地址空间,但操作系统通常会限制单个进程使用小于该空间的地址空间。
节点名称的长度 Erlang 节点名称具有以下形式:host@shortname 或 host@longname。节点名称在系统内用作原子,因此 255 的最大大小也适用于节点名称。
打开的端口 同时打开的 Erlang 端口的最大数量通常默认为 16,384。此限制可以在启动时配置。有关更多信息,请参见 ERTS 中 erl(1) 手册页中的 +Q 命令行标志。
运行时系统实例上的唯一本地端口标识符 在 64 位系统上,最多可以创建 2⁶⁰ - 1 个唯一端口标识符,而在 32 位系统上,最多可以创建 2²⁸ - 1 个唯一端口标识符。
打开的文件和套接字 同时打开的文件和套接字的最大数量取决于 可用 Erlang 端口的数量的最大值 以及特定于操作系统的设置和限制。
函数或 Fun 的参数数量 255
运行时系统实例上的唯一引用 每个调度程序线程都有自己的引用集,而所有其他线程都共享一个引用集。每个引用集包含 2⁶⁴ - 1 个唯一引用。也就是说,在运行时系统实例上可以产生的唯一引用的总数为 (NoSchedulers + 1) × (2⁶⁴ - 1)

如果调度程序线程每纳秒创建一个新的引用,那么最早在 584 年之后才会重复使用引用。也就是说,在可预见的未来,它们是足够唯一的。
运行时系统实例上的唯一整数 使用 erlang:unique_integer() BIF 创建了两种类型的唯一整数

1. 使用 monotonic 修饰符创建的唯一整数包含一组 2⁶⁴ - 1 个唯一整数。

2. 不使用 monotonic 修饰符创建的唯一整数包含每个调度程序线程一组 2⁶⁴ - 1 个唯一整数,以及其他线程共享的一组 2⁶⁴ - 1 个唯一整数。也就是说,不使用 monotonic 修饰符的唯一整数的总数为 (NoSchedulers + 1) × (2⁶⁴ - 1)

如果每纳秒创建一个唯一整数,那么最早在 584 年之后才会重复使用唯一整数。也就是说,在可预见的未来,它们是足够唯一的。

表 11.2:  系统限制