range本身几乎不占内存(仅存start/stop/step,约48–96字节),真正爆内存的是list(range(...))等强制展开操作,因list需存储每个int对象(cpython中≥28字节)及元数据。

range 本身不生成超大数组,它几乎不占内存;真正占用大量内存的是 list(range(...)) 这种显式转换操作。很多人误以为 “range(10**9)” 很重,其实它只存三个整数(start/stop/step),内存约 48–96 字节。问题出在把它当成“数组”来用——一旦调用 list()、json.dumps()、pandas.DataFrame() 或直接做切片赋值等,就会强制展开全部元素,瞬间爆内存。
为什么 list(range(n)) 会爆内存
Python 的 list 是真实容器,每个整数都是独立对象(CPython 中一个 int 至少占 28 字节),加上列表头开销:
-
range(10**7):≈ 48 字节 -
list(range(10**7)):约 280 MB(1000 万个 × 28 字节 + 元数据) -
list(range(10**9)):极大概率触发MemoryError,系统无法分配连续内存块
真正低内存的替代方案
不追求“一次性拿到所有数”,而是按需访问或流式处理:
-
直接用 range 对象:支持
len()、in、索引(r[1234567])、切片(返回新 range),全部 O(1) 时间且零额外存储 -
生成器表达式:如
(x * 2 for x in range(10**8)),仅保存迭代状态,内存恒定 ≈ 几百字节 -
array.array:适合纯数值场景,
array.array('i', range(10**7))占约 40 MB(紧凑 C int 存储) - numpy.memmap:数据存在磁盘,按需加载页,可处理 TB 级数组,内存占用稳定在几 MB
哪些操作会让 range “悄悄变重”
看似无害,实则立刻放弃惰性优势:
-
list(range(10**6))—— 最常见错误 -
json.dumps(range(10**5))—— json 不识别 range,自动转 list -
pd.Series(range(10**6))—— pandas 内部强制展开 -
print(range(10**6))—— 某些 IDE 会预取前若干项,间接触发部分迭代
需要随机访问又想省内存?试试 numpy.arange + memmap
如果业务真要像数组一样索引、切片、广播运算,但数据太大放不下 RAM:
- 用
np.memmap('data.dat', dtype='int64', mode='w+', shape=(10**9,))创建内存映射文件 - 再用
np.arange分块写入,或直接计算后存入对应位置 - 后续读取
mmapped_arr[123456789]时,操作系统只加载对应磁盘页,不全载入内存











