如何避免树莓派Pico上MicroPython垃圾回收延迟及内存泄漏?
问题与解决方案
问题描述
在树莓派Pico上使用MicroPython处理脉冲波(17ms高电平、3ms低电平)时,遇到两个核心问题:
- 垃圾回收(GC)触发时会导致输出异常延迟约6ms,超出需求范围
- 禁用GC(
gc.disable())后,程序仅运行约1秒就因内存耗尽崩溃
以下测试代码仅更新类实例属性,却出现持续内存增长:
from gc import mem_alloc from time import ticks_us, ticks_diff class Example_class: def __init__(self,a): self.a = a self.b = 1 example_object = Example_class(1) start_time = ticks_us() while True: example_object.a=0.000001 * ticks_diff(ticks_us(),start_time) m0 = mem_alloc() # 用于演示内存变化 example_object.b=example_object.a*1 m1 = mem_alloc() # 用于演示内存变化 print(m1-m0) # 输出每次循环新增内存 print(mem_alloc()) # 输出当前已分配内存
测试发现:
print(m1-m0)始终返回16,说明每次循环都新增16字节内存mem_alloc()结果持续增长,禁用GC后程序数秒内崩溃- 将乘数
0.000001改为1后问题消失,random.randint(0,1)等操作也会引发类似内存增长
问题原因
- 浮点数的不可变性:MicroPython中浮点数是不可变对象,每次浮点数计算(如
0.000001 * ticks_diff(...))都会在堆上创建新的浮点数对象,旧对象被丢弃后,若GC禁用则无法被回收,导致内存持续累积。 - 小整数对象池复用:当乘数改为1时,计算结果为整数,MicroPython对小整数(通常是-5到256)采用对象池复用机制,不会创建新对象,因此无内存增长。
- 额外操作的对象创建:
random.randint或print等操作会创建临时字符串/对象,同样会占用堆内存,在GC禁用时无法回收。
解决方案
1. 完全用整数运算替代浮点数
浮点数是内存增长的核心原因,将所有计算转换为整数操作:
- 保留微秒级整数计时(
ticks_us返回的整数),避免浮点缩放。例如将0.000001 * ticks_diff(...)改为ticks_diff(...) // 1000000(得到秒级整数),或直接用微秒整数进行后续逻辑计算。 - 示例修改:
from gc import mem_alloc from time import ticks_us, ticks_diff class Example_class: def __init__(self,a): self.a = a self.b = 1 example_object = Example_class(1) start_time = ticks_us() while True: # 用整数除法替代浮点乘法,得到秒级整数 example_object.a = ticks_diff(ticks_us(), start_time) // 1000000 m0 = mem_alloc() example_object.b = example_object.a * 1 m1 = mem_alloc() print(m1 - m0) # 此时输出应为0,无新增内存
2. 手动控制GC触发时机
不要完全禁用GC,而是在脉冲波的低电平时间段(3ms)手动调用gc.collect(),这段时间对输出延迟不敏感:
import gc from machine import Pin from time import ticks_us, ticks_diff, sleep_ms gc.disable() # 先禁用自动GC pulse_pin = Pin(15, Pin.OUT) while True: # 输出17ms高电平(核心逻辑,无GC) pulse_pin.value(1) # 执行高电平期间的逻辑,确保无内存泄漏 # ... # 进入3ms低电平,手动触发GC pulse_pin.value(0) gc.collect() sleep_ms(3) # 补足低电平时间
3. 移除不必要的调试操作
print语句会创建大量临时字符串对象,调试完成后必须移除,避免额外内存消耗。
4. 预分配必要对象(如必须用浮点数)
若业务逻辑必须使用浮点数,可预先创建浮点数变量并复用,但MicroPython浮点数不可变,因此需用其他方式优化:
- 例如将浮点数计算结果存储到预先分配的列表或对象的属性中,避免每次创建新对象(实际效果有限,优先推荐整数方案)。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

