OCaml 中占用 8 位的原语

Posted

技术标签:

【中文标题】OCaml 中占用 8 位的原语【英文标题】:Primitive that occupies 8 bits in OCaml 【发布时间】:2022-01-22 20:17:12 【问题描述】:

我惊讶地发现,在使用 Spacetime 分析我的 OCaml 时,我的 char 甚至 bool 数组使用一个词来表示每个元素。这在我的 64 位机器上是 8 个字节,会导致使用太多内存。

我已尽可能将char array 替换为Bytes,但我也有char list 和动态数组(char BatDynArray)。是否有一些原始或通用的方法可以用于所有这些矢量数据结构并获得底层的 8 位表示?

【问题讨论】:

你看过stdlib的Bigarray(或者上面的辅助模块,比如BigstringBigstringafCtypes等)吗?和Bytes 一样,它可以用char 进行结构化,但它也可以有效地表示多维数组。 对不起,我第一次看错了你的问题,写了一个有点跑题的答案:我现在编辑了。简短的回答是:使用标准库中的Buffer。或者@VPhantom 所说的Bigarray 哇哦,谢谢@VPhantom。 Bigarray 似乎是要走的路。看起来它支持 8、16 和 32 位整数的打包版本。它不会按需增长,但是 - 这没什么大不了的 - 我将使用 Bigarray 作为构建块来实现一个动态数组。 【参考方案1】:

编辑:我读你的问题太快了:你可能已经知道了;对不起!这是一个更有针对性的答案。

我认为存储不同数量的字符(即在执行 IO 时)的一般建议是使用可能可调整大小的缓冲区。 Module Buffer 实现了一个可调整大小的字符缓冲区,这比 char list(糟糕的设计,可能除了非常短的列表)和 char BatDynArray(它们的通用性在这里会导致内存损失,正如您所注意到的)都好。


以下是原答案。

这是由于值的统一表示。无论它们的类型如何,每个 OCaml 值都是一个机器字:立即数(任何可以适合 31 位或 63 位整数的值,例如 intcharbool、等等),或者一个指向block的指针,即一个机器字序列(一个C-fashion数组),前缀为一个header。当值是指向块的指针时,我们说它是“装箱的”。

OCaml arrays 的单元格始终是机器字。

在 OCaml 中,就像在 C++ 中一样,但没有临时重载,我们只在我们真正想要节省空间的少数情况下定义 array 的特化。在你的情况下:

使用string(不可变)或bytes(可变)或Buffer.t可变可附加和可调整大小)代替char array;这些类型向 GC 发出信号,表明它们的单元格永远不是指针,因此它们可以打包任意二进制数据; 不幸的是,标准库没有专门针对bool array,但我们可以实现一个(例如使用bytes);您可以在多个第三方库中找到一个,例如 package containers-data 中的 module CCBV(“bitvectors”)。

最后,你可能还没有意识到,但floats 被装箱了!这是因为它们需要 64 位(IEEE 754 双精度),这比可用于立即数的 31 位甚至 63 位多。幸运的是(?),编译器和运行时有一些 adhoc-ery 来尽可能避免装箱。特别是float array 进行了特别优化,因此它存储原始浮点数而不是指向它们的指针。


更多背景知识:我们可以通过测试一位来区分指针和立即数。统一表示对于以下方面非常有价值:

实现垃圾回收, 免费的参数多态性(与 C++ 等模板语言相比,没有代码重复)。

【讨论】:

谢谢!您的答案中有很多有用的见解。使用我尝试过的Buffer 的问题是您无法在其中设置字符,至少效率不高。所以据我所知,没有 Bytes.set 等价物。 哦!没错,Buffer 的 API 是仅附加的。这对我来说是一个惊喜。快速查看the code:实现只是bytes 的包装,根据需要重新分配,我看不出暴露Buffer.get,set 会导致什么问题……也许是公关?

以上是关于OCaml 中占用 8 位的原语的主要内容,如果未能解决你的问题,请参考以下文章

32位操作系统中,int,long占用4字节,short占用2字节…… 那64位的呢

基本数据类型占用的字节数

Java原语可以被视为轻对象吗?

生产者消费者模式(转)

为啥这个函数会占用大量内存?

图片占用内存计算