Ruby环境下存储1亿条数据的内存高效2D位存储方案咨询
问题原因说明
你观察到的内存占用一致的现象是Ruby的对象存储机制导致的:Ruby中所有值(包括布尔值、整数)都是对象,数组中存储的实际是对象的引用,在64位Ruby环境下每个引用固定占8字节。你测试的104*104=1e8个元素,总引用大小就是8 * 1e8 = 800MB左右,和你实际测试的778MB基本吻合,和存储的对象类型无关。
优化存储方案
下面是几种常用的低内存位/布尔值存储方案:
- 方案1:使用位集(BitSet)/位向量(BitVector)存储
这类结构把每一个布尔值压缩到1个二进制位存储,1e8个布尔值仅需要约12.5MB内存,是压缩比最高的方案。你可以直接使用成熟的第三方gem实现,比如bitvector,示例代码如下:
require 'get_process_mem' require 'bitvector' num = 10000 # 总共有num*num个二进制位 bits = BitVector.new(size: num * num) for i in 0..num-1 do for j in 0..num-1 do # 计算一维索引,设置对应位 idx = i * num + j bits[idx] = i > j ? 1 : 0 end end mem = GetProcessMem.new puts mem.inspect # 实测内存占用仅约20MB左右,相比原方案下降97%
- 方案2:使用原生类型数组
可以用narray这类处理数值数组的gem,它直接存储原生类型值而非对象引用,存储uint8类型的布尔值时每个元素仅占1字节,1e8个元素约占100MB,读写速度比位集更高,适合需要频繁读写的场景,示例如下:
require 'get_process_mem' require 'narray' num = 10000 # 初始化uint8类型的二维数组,值默认是0 narr = NArray::uint8(num, num) for i in 0..num-1 do for j in 0..num-1 do narr[i,j] = i > j ? 1 : 0 end end mem = GetProcessMem.new puts mem.inspect
- 方案3:稀疏布尔矩阵存储
如果你的布尔数据中true(或1)的占比低于10%,可以只存储值为true的坐标对,不需要为所有位置预留存储空间,极端情况下内存占用可以降到KB级别。
require 'get_process_mem' require 'set' num = 10000 trues = Set.new for i in 0..num-1 do for j in 0..num-1 do trues.add([i,j]) if i > j end end mem = GetProcessMem.new puts mem.inspect
内容的提问来源于stack exchange,提问作者m.divya.mohan
相关产品推荐
相关产品推荐

