当前位置:首页>python>从 RAM 到 Flash:MicroPython 嵌入式内存优化的底层逻辑与实践

从 RAM 到 Flash:MicroPython 嵌入式内存优化的底层逻辑与实践

  • 2026-08-18 23:12:11
从 RAM 到 Flash:MicroPython 嵌入式内存优化的底层逻辑与实践

1.前置概念

MicroPython 的核心应用场景是微控制器(如树莓派 Pico、ESP32、ESP8266),这类设备的硬件资源与电脑 / 服务器存在数量级的差距 —— 通常 RAM(运行内存)只有几十 KB 到几百 KB,Flash(存储内存)也仅几 MB。而 Python 代码本身具有动态性,运行时会占用一定的内存资源,因此在微控制器上使用 MicroPython 时,内存优化是保证程序稳定运行的关键。本文将详细介绍 MicroPython 内存优化的方法,其中会对新手不易理解的专有名词进行标注解释,同时为核心知识点提供可在 REPL(MicroPython 交互式命令行)中运行的测试代码,帮助你边学边验证。

在学习具体优化方法前,先理解以下核心专有名词,能让后续内容更易理解:

  • RAM(随机存取存储器)
    :又称运行内存,是微控制器用于临时存储运行中的代码、数据的区域,特点是读写速度快,但断电后数据丢失,且容量极小(树莓派 Pico 的 RAM 为 264KB)。
  • Flash(闪存)
     :又称存储内存,是微控制器用于永久存储固件、用户代码、数据的区域,特点是断电后数据不丢失,容量比 RAM 大,但读写速度较慢(树莓派 Pico 的 Flash 为 2MB)。
  • 字节码
    :MicroPython 不会直接执行人类编写的源码(.py 文件),而是先将源码编译为一种介于源码和机器码之间的中间代码(即字节码),再由 MicroPython 解释器执行。字节码的体积更小,执行效率更高。
  • 固件
    :烧录到微控制器 Flash 中的底层软件,包含 MicroPython 解释器、硬件驱动等核心功能,是 MicroPython 运行的基础。
  • REPL
    :即 Read-Eval-Print Loop(读取 - 执行 - 打印循环),是 MicroPython 的交互式命令行工具(如 Thonny 的 Shell 面板、串口工具的交互窗口),可以逐行输入代码并立即执行,是新手调试、测试代码的必备工具。
  • SPI 总线
    :一种串行外设接口(Serial Peripheral Interface),是微控制器与外部设备(如 SD 卡、传感器)通信的常用协议,具有接线简单、传输速度快的特点。

2.优化方法

2.1 基本概念

在学习具体优化方法前,先理解以下核心专有名词,能让后续内容更易理解:

  • RAM(随机存取存储器)
     :又称运行内存,是微控制器用于临时存储运行中的代码、数据的区域,特点是读写速度快,但断电后数据丢失,且容量极小(树莓派 Pico 的 RAM 为 264KB)。
  • Flash(闪存)
     :又称存储内存,是微控制器用于永久存储固件、用户代码、数据的区域,特点是断电后数据不丢失,容量比 RAM 大,但读写速度较慢(树莓派 Pico 的 Flash 为 2MB)。
  • 字节码
    :MicroPython 不会直接执行人类编写的源码(.py 文件),而是先将源码编译为一种介于源码和机器码之间的中间代码(即字节码),再由 MicroPython 解释器执行。字节码的体积更小,执行效率更高。
  • 固件
    :烧录到微控制器 Flash 中的底层软件,包含 MicroPython 解释器、硬件驱动等核心功能,是 MicroPython 运行的基础。
  • REPL
    :即 Read-Eval-Print Loop(读取 - 执行 - 打印循环),是 MicroPython 的交互式命令行工具(如 Thonny 的 Shell 面板、串口工具的交互窗口),可以逐行输入代码并立即执行,是新手调试、测试代码的必备工具。
  • SPI 总线
    :一种串行外设接口(Serial Peripheral Interface),是微控制器与外部设备(如 SD 卡、传感器)通信的常用协议,具有接线简单、传输速度快的特点。

2.2 安装 SD 卡

支持 MicroPython 的开发板可以通过插入 SD 卡的方式扩展内存,首先需要将卡格式化为 FAT/FAT32格式(一种通用的文件系统格式,被绝大多数设备支持,也是 MicroPython 识别 SD 卡的必要格式) 。通常使用 SPI 总线 挂在 SD 卡,插卡后 MicroPython 会从 SD 卡启动,如果 SD 卡上有 boot.py 和 main.py,在启动时也会自动执行。

我们也可以从内部 flash 启动而又使用 SD 卡保存数据,这时需要在 SD 卡根目录中设置一个 SKIPSD 文件,当系统启动时检查到 SD 上存在这个文件,就会忽略 SD 卡,仍然从内部 Flash 启动。

关于 MicroPython 在 SD 卡上的使用,可以看下面的教程:

08 SPI 串行外设接口-文档教程初稿

在树莓派 pico 上使用 SD 卡可以参考教程:

  • Micropython SD 卡操作 https://blog.csdn.net/gene8888/article/details/89599251
  • 树莓派 pico 使用 spi 操作 sd 卡 
  • 使用 SPI 方式挂载 SD 卡 https://pico.nxez.com/2018/12/30/mount-the-sd-card-using-spi.html
  • 树莓派 Pico 与 MicroSD 卡模块接口 https://blog.csdn.net/yuanzywhu/article/details/131592815
  • MicroPython 设置忽略 SD 卡启动 https://pico.nxez.com/2018/12/21/micropython-settings-ignore-sd-card-boot.html

2.3 使用 frozen 模块和 frozen 字节码

实际开发中我们往往有多个.py 文件存放不同的代码,main.py 文件运行主要的业务流程,main.py 通过 import 语句引用其他.py 文件 / 模块 / 包完成整个工作(例如其他传感器的类)。main.py 文件和其他文件往往都处于开发板文件系统的根目录。

从文件系统上的 Python 文件加载模块和包来存储和运行代码有一些很大的限制,这些 Python 代码必须由 MicroPython 的解释器加载和处理,该过程需要耗费时间和内存,甚至有的情况下这些代码文件太大,无法加载到 Flash 内存并由 MicroPython 的解释器处理。Frozen 模块(冻结模块)和 Frozen 字节码(冻结字节码)可以将 Python 代码编译为 native 代码 / 字节码并将其和固件存储,这样做可以压缩内存。一旦代码被冻结,MicroPython 就可以快速加载和解释它,而无需太多的内存和处理时间。

2.3.1 Python 字节码

MicroPython 代码先被编译为字节码后,再由解释器来执行字节码,MicroPython 的字节码是一种类似汇编指令的中间语言,一个 MicroPython 语句会对应若干字节码指令,解释器顺序执行字节码指令,从而完成程序执行。

代码被预编译为字节码,避免了在加载时编译 MicroPython 源代码的需要。字节码可以直接从 Flash 执行,而不需要复制到 RAM 中。同样,任何常量对象(如字符串、元组等)也从 ROM 加载。这可以使得更多的内存可用于应用程序。在没有文件系统的设备上,这是加载 Python 代码的唯一方式。

2.3.2 生成冻结模块和字节码的步骤

一个生成冻结模块和字节码的步骤通常如下:

  • 克隆 MicroPython 源代码存储库
  • 获取(特定于平台的)工具链以构建固件
  • 构建交叉编译器
  • 将要冻结的模块放在指定目录中(取决于模块是作为源还是字节码冻结)
  • 构建固件。可能需要特定命令来构建任一类型的冻结代码
  • 将固件刷入设备

2.3.3 MicroPython 的 frozen 的主要特点

MicroPython 的 frozen 的主要特点是:

  • 它可以通过一个 “清单” 文件来列出要冻结到固件中的 Python 文件,清单文件是一个包含一系列函数调用的 Python 文件,可以在板子定义中编写,也可以编写一个独立的清单文件,并与现有的板子定义一起使用
  • 它可以定义对来自 micropython-lib 的库以及文件系统上的 Python 文件的依赖关系,以及对其他清单文件的依赖关系
  • 它可以让用户在 Python 中创建和操作各种类型的对象,如数字、字符串、列表、字典、函数、模块等

使用冻结模块和冻结字节码可以参考教程:

  • Freezing the byte-code of a module and include it in the firmware doesn't work https://github.com/bbcmicrobit/micropython/issues/555
  • Frozen Modules https://learn.adafruit.com/micropython-basics-loading-modules/frozen-modules
  • How to freeze module for ESP32 https://forum.micropython.org/viewtopic.php?t=12268

2.4 使用.mpy 文件

将 python 模块预编译为字节码(也称为 .mpy 文件(MicroPython 的预编译字节码文件格式,区别于标准 Python 的.pyc 文件)),然后将其复制到开发板上。这样做的优点是可以跳过 开发板上的预编译阶段,从而避免在此过程中没有 RAM 资源。不幸的是,这种方法仍然需要开发板将模块加载到 RAM 中。

将 python 模块转换为 .c 文件,该文件被编译到固件本身中。具有上述方法的优点 + 具有从闪存运行模块而不是将其加载到 RAM 中的优点。

.mpy 文件生成与使用步骤可以参考:如何加快 MicroPython 的运行速度

2.5 使用 const 常量

2.5.1 MicroPython 命名空间和作用域

MicroPython 中所有加载到 RAM 的模块都会放在 sys.modulessys.modules 是一个全局字典,从 python 程序启动就加载到了内存,用于保存当前已导入 (加载) 的所有模块名和模块对象。在 MicroPython 的模块查找中,它起到缓存作用,避免了模块的重复加载。

程序在导入某个模块时,会首先查找 sys.modules 中是否包含此模块名,若存在,则只需将模块的名字加入到当前模块的 Local 命名空间中;若不存在,则需要从 sys.path 目录中按照模块名称查找模块文件,找到后将模块加载到内存,并加入到 sys.modules 字典,最后将模块的名字加入当前模块的 Local 命名空间中。接下来,我们在终端的 REPL 中进行测试:

import sys# sys.modules显示当前已导入 (加载) 的所有模块名和模块对象print("Initial modules:")print(list(sys.modules.keys()))# 定义全局变量global_var = "I am a global variable"# enclosing_var 闭包外层变量# local_var 函数inner_function内部局部变量# len 是内置函数# 尝试修改全局变量global_var (不使用global会创建局部变量)# 闭包外层无法访问内部局部变量defscope_demo():    enclosing_var = "I am an enclosing variable (outer of closure)"definner_function():        local_var = "I am a local variable"print("Local variable:", local_var)print("Enclosing variable:", enclosing_var)print("Global variable:", global_var)print("Built-in function example:"len("test"))try:            global_var = "Trying to modify"except:pass    inner_function()try:print(local_var)except:print("Cannot access local variable")# 使用global修改全局变量defmodify_global():global global_var    global_var = "Modified global variable"print("Inside function:", global_var)# 多层嵌套中的nonlocal使用# 内部middle()函数和inner()函数中修改嵌套作用域中的变量outer_vardefnonlocal_demo():    outer_var = "Outer layer"defmiddle():nonlocal outer_var        outer_var = "Modified by middle layer"definner():nonlocal outer_var            outer_var = "Modified by inner layer"        inner()print("In middle:", outer_var)    middle()print("In nonlocal_demo:", outer_var)# 作用域演示print("\n=== Scope Demonstration ===")scope_demo()print("Access in global scope:", global_var)# 修改全局变量print("\n=== Modify Global Variable ===")modify_global()print("In global scope:", global_var)# nonlocal演示print("\n=== nonlocal Demonstration ===")nonlocal_demo()# 尝试访问内置作用域import builtinsprint("Built-in module:", builtins)

终端运行,输出如下:

2.5.2 const 常量的定义与优化原理

常量是指在程序执行期间不会发生变化的值,一般用于存储不可更改的数据,比如数学常数、配置信息等。在单片机中常量会保存在 ROM/Flash 闪存中,可以节省 RAM 空间。

MicroPython 中的关键字 const 用于声明表达式是常量,以便编译器对其进行优化,在将常量分配给变量的两种情况下,编译器将避免通过替换常量的文字值来编写对常量名称的查找。这可以节省字节码,从而节省 RAM。

不过需要注意的是,使用关键字 const 时候,需要使用 mpy-cross 工具编译为 mpy 文件才能发挥其作用。

from micropython import const# 垃圾回收模块,用于查看内存使用情况import gc# 第一步:查看初始内存使用情况# 强制垃圾回收,释放无用内存gc.collect()initial_free = gc.mem_free()print(f"Initial free RAM: {initial_free} bytes")# 第二步:定义const常量# 公开常量(模块外能访问,仅占极少量RAM)CONST_X = const(123)CONST_Y = const(2 * 123 + 1)# 私有常量(以下划线开头,模块外不能访问,完全不占用RAM)_COLS = const(0x10)ROWS = const(33)# 第三步:使用常量a = ROWSb = _COLSprint(f"CONST_X: {CONST_X}, CONST_Y: {CONST_Y}")print(f"a: {a}, b: {b}")# 第四步:查看定义常量后的内存使用情况gc.collect()after_free = gc.mem_free()print(f"Free RAM after defining constants: {after_free} bytes")print(f"RAM change: {after_free - initial_free} bytes (positive means memory freed)")# 补充:对比普通变量与const常量的区别# 普通变量,存储在RAM中normal_var = 123  gc.collect()after_normal = gc.mem_free()print(f"Free RAM after defining normal variable: {after_normal} bytes")print(f"Normal variable uses {after_free - after_normal} more bytes than const")

ROWS 值将占用至少两个机器字,全局字典中的键和值各一个。字典中的存在是必要的,因为另一个模块可能会导入或使用它。可以通过在名称前面添加下划线来保存此 RAM,如 _COLS 所示:此符号在模块外部不可见,因此不会占用 RAM。

终端运行结果如下:const () 的参数必须是任何在编译时计算结果为整数的值。

from micropython import constROWS = const(33)# 下面用法报错COLS = const(0x10+ROWS)# 正确用法COLS = const(0x10+33)

终端输出如下:

2.6 减少不必要的对象创建

在 MicroPython 中,对象(如字符串、列表、字典、字节数组、数值容器等)的创建会占用 RAM 资源。由于微控制器的 RAM 容量极小,频繁创建和销毁对象不仅会直接消耗内存,还会导致内存碎片化(即 RAM 中出现大量小的空闲内存块,无法被大对象使用),最终引发内存不足的问题。需要注意的是,标准 Python 中的 sys.getsizeof() 函数在 MicroPython 中大部分平台不支持(这是 MicroPython 的特性,为了精简固件),因此我们可以通过 struct 模块将变量 / 数据打包为字节流,再通过 len() 函数获取字节流的长度,以此来测试数据占用的字节大小;同时结合 gc 模块(垃圾回收)查看 RAM 的实际使用变化,完成优化前后的对比。

2.6.1 字符串操作优化(避免临时字符串对象)

MicroPython 中的字符串是不可变对象,使用 + 拼接字符串时,每一次 + 都会创建一个临时字符串对象(比如 "a"+"b"+"c" 会先创建 "ab",再创建 "abc",共 2 个临时对象),这些临时对象会占用额外的 RAM,且会被垃圾回收器频繁清理,影响性能。

优化思路:

  • 使用字符串直接拼接(编译时合并,无临时对象);
  • 使用 join() 方法(仅创建一个最终字符串对象);
  • 使用多行字符串(""" 或 ''',编译时合并)。
# 静态字符串拼接(编译时合并,无临时对象)static_str = "MicroPython" "Memory" "Opt"print("Static string:", static_str)# 动态字符串(推荐format,减少临时对象)temp = 25.5press = 101325dynamic_str = "Temp: {:.2f}, Press: {:d}".format(temp, press)print("Dynamic string:", dynamic_str)

2.6.2 硬件操作中的缓冲区复用(UART/SPI/I2C 场景)

在 MicroPython 的硬件操作中(如 SPI 读取传感器数据、UART 接收数据),频繁创建新的字节缓冲区(bytearray/bytes)会占用大量 RAM。例如,每次读取传感器都创建 buf = bytearray(10),循环 100 次就会创建 100 个缓冲区对象。

我们可以提前分配一个缓冲区,在循环 / 多次操作中复用,仅创建一次对象,彻底避免临时缓冲区的创建。

下面我们预分配串口接收缓冲区,循环中复用,避免重复创建 bytearray

from machine import UART, Pin# 初始化UARTuart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))# 预分配缓冲区(仅创建1次)uart_buf = bytearray(16)# 循环接收(复用缓冲区)for _ inrange(5):    uart.readinto(uart_buf)print("UART data:", uart_buf)

下面,我们预分配 SPI 读写缓冲区,复用减少内存开销。

from machine import SPI, Pin# 初始化SPIspi = SPI(0, baudrate=1000000, sck=Pin(2), mosi=Pin(3), miso=Pin(4))# 预分配缓冲区spi_buf = bytearray(8)# 循环读写(复用缓冲区)for _ inrange(5):    spi.readinto(spi_buf)print("SPI data:", spi_buf)

2.6.3 数值存储优化(用 struct/bytearray 代替列表)

在 MicroPython 中,列表存储数值(如 [1, 2, 3, 255])会占用较多 RAM,因为列表中的每个整数对象都有额外的内存开销(比如一个 int 类型在 MicroPython 中占 4 字节,而列表本身还有指针开销)。

优化思路:

  • 使用 struct 模块将多个数值打包为字节流(比如将 4 个整数打包为 4 字节的字节流);
  • 使用 bytearray(可变字节数组)存储小数值(0-255),每个元素仅占 1 字节,远少于列表中的整数;
  • str
     与 bytes 可通过 encode()/decode() 转换,但转换会创建新对象,需避免频繁操作。
# 1. str vs bytes(内存占用一致,ASCII场景)# String (ASCII)s = 'the quick brown fox'# Bytes (1 byte per char)b = b'the quick brown fox'print("String:", s)print("Bytes:", b)# 2. 字符串与字节的转换(注意:转换会创建新对象)# str -> bytess_to_b = s.encode()  # bytes -> strb_to_s = b.decode()  print("Str->Bytes:", s_to_b)print("Bytes->Str:", b_to_s)# 3. bytes支持字符串方法(如lstrip)foo = b'  empty whitespace'foo_stripped = foo.lstrip()print("Stripped bytes:", foo_stripped)

终端运行,输出如下:

2.6.4 避免循环中的临时容器创建

在循环中频繁创建临时容器(如 for _ in range(100): temp = [1,2,3])会创建大量临时对象,占用 RAM。优化思路是将临时容器移到循环外,复用对象,或使用生成器 / 迭代器代替临时列表。

import gcimport struct# 初始化垃圾回收,建立测试基线gc.collect()ram_init = gc.mem_free()# 定义循环次数(模拟多次迭代场景)loop_times = 100# ---------------------- 低效实现:循环内创建临时列表 ----------------------# 循环内每次创建新的列表容器,产生大量临时对象gc.collect()ram_slow_before = gc.mem_free()total_slow = 0# 每次循环创建新列表[1,2,3,4,5]# struct测试列表数据的字节大小(打包为5个整数,用'i'格式)for _ inrange(loop_times):    temp_list = [12345]    total_slow += sum(temp_list)    size_slow = len(struct.pack("5i", *temp_list))# 记录低效实现后的RAMram_slow_after = gc.mem_free()# ---------------------- 高效实现1:循环外创建列表,复用容器 ----------------------# 列表仅创建一次,循环内复用gc.collect()ram_fast1_before = gc.mem_free()total_fast1 = 0# 临时列表移到循环外(仅创建1次)# struct测试复用列表的字节大小(与低效实现一致)temp_list_reuse = [12345]for _ inrange(loop_times):    total_fast1 += sum(temp_list_reuse)    size_fast1 = len(struct.pack("5i", *temp_list_reuse))# 记录高效实现1后的RAMram_fast1_after = gc.mem_free()# ---------------------- 高效实现2:使用生成器,替代临时列表 ----------------------# 定义生成器函数(仅创建一次,循环内复用迭代器)# 直接yield元素,避免元组创建defnum_generator():yield1yield2yield3yield4yield5# 生成器不创建完整列表,仅迭代生成元素,内存开销最低gc.collect()ram_fast2_before = gc.mem_free()total_fast2 = 0# 生成器表达式(无临时列表对象)# struct测试生成器数据的字节大小(打包为5个整数)for _ inrange(loop_times):    total_fast2 += sum(num_generator())    size_fast2 = len(struct.pack("5i"12345))# 记录高效实现2后的RAMram_fast2_after = gc.mem_free()# 输出测试结果(无中文)print("Slow total:", total_slow)print("Slow RAM change:", ram_slow_before - ram_slow_after)print("Slow data size:", size_slow)print("Fast1 total:", total_fast1)print("Fast1 RAM change:", ram_fast1_before - ram_fast1_after)print("Fast1 data size:", size_fast1)print("Fast2 total:", total_fast2)print("Fast2 RAM change:", ram_fast2_before - ram_fast2_after)print("Fast2 data size:", size_fast2)

终端运行结果如下:我们可以看到:

  • 每次循环创建新列表对象:内存消耗为 10528 字节;
  • 循环外创建列表复用容器:内存消耗为 5888 字节;
  • 使用生成器:内存消耗为 8720 字节。

在小数据量(5 个固定数)重复 100 次的场景下,列表复用确实比生成器更省内存;当需要处理大量数据或流式数据时,生成器避免了一次性加载所有数据。

2.6.5 避免运行时编译器执行(eval/exec

eval()/exec() 会在运行时调用 MicroPython 编译器,创建大量临时对象,消耗大量 RAM;直接计算或使用 json 序列化替代,可减少内存开销。

import gcimport structimport json# ---------------------- 低效:使用eval ----------------------gc.collect()ram_eval_before = gc.mem_free()# 避免使用eval,此处仅作对比res_eval = eval("1 + 2 * 3 + 4 / 2")ram_eval_after = gc.mem_free()# ---------------------- 高效:直接计算 ----------------------gc.collect()ram_calc_before = gc.mem_free()res_calc = 1 + 2 * 3 + 4 / 2ram_calc_after = gc.mem_free()# ---------------------- 高效:ujson序列化 ----------------------gc.collect()ram_json_before = gc.mem_free()# 序列化data = {"temp": 25.5, "press": 101325}json_data = json.dumps(data)# 反序列化size_json = len(struct.pack(f"{len(json_data.encode())}s", json_data.encode()))data_loaded = json.loads(json_data)ram_json_after = gc.mem_free()# 输出测试结果print("Eval RAM change:", ram_eval_before - ram_eval_after)print("Calc RAM change:", ram_calc_before - ram_calc_after)print("JSON size:", size_json)print("JSON RAM change:", ram_json_before - ram_json_after)

终端运行结果如下:我们可以看到,动态解析(eval())和 JSON 处理会创建大量隐藏的临时对象:

  • eval("1+2*3+4/2")
     虽然结果相同但消耗 592 字节内存,比直接计算(384 字节)多出 208 字节;
  • 而 JSON 序列化 31 字节数据却消耗 1488 字节内存,因为解析字符串、创建中间字典、转换浮点数等每个步骤都产生碎片化分配,最终实际内存开销是数据大小的 48 倍。

这正是微控制器上内存碎片化的典型表现——表面简单的操作背后隐藏着指数级的内存消耗。

2.6.6 在闪存中存储字符串(qstr 机制)

MicroPython 的 qstr 量化字符串机制会将重复的字符串存储在闪存中,而非 RAM,减少 RAM 占用,我们可以通过 micropython.qstr_info() 查看字符串存储状态,用 struct 测试字符串字节大小,用 gc 查看 RAM 变化。

import gcimport structimport micropython# 初始化垃圾回收gc.collect()ram_init = gc.mem_free()# 定义测试字符串(会被qstr机制处理)s1 = "MicroPython"# 重复字符串,复用闪存中的qstrs2 = "MicroPython"# struct测试字符串字节大小size_s = len(struct.pack(f"{len(s1.encode())}s", s1.encode()))# 打印qstr信息(1表示详细输出)micropython.qstr_info(1)# 记录RAMram_after = gc.mem_free()# 输出测试结果print("String size:", size_s)print("RAM free:", ram_after)

终端输出结果如下:我们可以看到,s1 和 s2 两个字符串内容相同,都是 "MicroPython",MicroPython 的 qstr 机制会重用相同字符串,实际上 s1 和 s2 指向同一个内存中的字符串对象,同时节省了重复存储相同字符串的内存。

qstr 信息分析如下:

>>> micropython.qstr_info(1)qstr pool: n_pool=1, n_qstr=5, n_str_data_bytes=26, n_total_bytes=170Q(ram_init)Q(s1)Q(s2)Q(size_s)Q({}s)

关键信息解析:

  • n_pool=1:有 1 个 qstr 池;

  • n_qstr=5:当前有 5 个驻留的字符串;

  • n_str_data_bytes=26:字符串数据总大小 26 字节;

  • n_total_bytes=170:qstr 系统总占用 170 字节(qstr 管理结构本身有约 144 字节的开销)。

    并且列出的 5 个 qstr

  • ram_init:变量名(8 字符);

  • s1:变量名(2 字符);

  • s2:变量名(2 字符);

  • size_s:变量名(5 字符);

  • {}s:format 字符串的一部分(3 字符)。

但是,"MicroPython" 这个字符串没有在列出的 qstr 中,是因为 MicroPython 将它作为只读数据存储在 Flash 中,而不是 RAM 中。

2.7 堆与垃圾回收机制

堆是一块动态分配的内存区域,用于存储程序运行时创建的对象实例和动态数据结构(比如 Python 中的列表、字典、自定义类的实例):

  • 堆的大小不是固定的,会根据程序需求动态扩展(受限于系统总内存);
  • 在 Python、Java 等语言中,堆的分配是由语言的虚拟机(VM)自动完成的,开发者无需手动申请内存。

当你执行 lst = [1,2,3] 时,Python 会:

  • 在堆中分配一块内存,存储列表 [1,2,3] 的对象数据;
  • 在栈中分配一个变量 lst,存储的是堆中该对象的内存地址(引用)。也就是说,变量 lst 只是一个「指针」,指向堆中的实际数据。

堆中的对象如果没有任何引用指向它(即程序无法再访问到该对象),这个对象就成为「垃圾」:例如执行 lst = None 后,原本堆中的 [1,2,3] 对象就失去了引用,变成垃圾。

MicroPython 中 GC 垃圾回收可以自动识别并清理堆中的垃圾对象,释放占用的内存,避免内存泄漏(内存被无用对象一直占用,导致程序可用内存越来越少,最终崩溃)。垃圾回收的触发方式包括以下两种:

  • 自动触发
    :当堆内存占用达到阈值、或对象引用计数为 0 时,语言引擎自动触发 GC。
  • 手动触发
    :开发者可以通过代码主动调用 GC(比如 Python 中的 gc.collect())。

MicroPython 的 gc 模块有下面的常用的核心方法:

下面是我们的测试代码:

# 导入gc模块,用于操作垃圾回收(mpy版)import gc# 1. 查看自动GC是否开启(部分mpy版本支持)print(gc.isenabled())# 2. 禁用自动GC,方便手动控制测试过程gc.disable()print(gc.isenabled())# 3. 查看初始的空闲堆内存和已分配堆内存(mpy专属方法)print(f"Free heap: {gc.mem_free()} bytes")print(f"Allocated heap: {gc.mem_alloc()} bytes")# 4. 演示gc.threshold()方法:设置并查询GC分配阈值(mpy专属方法)# 设置阈值为1024字节,累计分配1024字节后触发GC(提前回收减少碎片)gc.threshold(1024)# 无参数时查询当前阈值current_threshold = gc.threshold()  print(f"Current GC threshold: {current_threshold} bytes")# 5. 创建普通对象,占用堆内存(变量是栈中的引用,指向堆对象)# 创建更大的列表,内存变化更明显obj1 = [12345]  obj2 = {"name""test""age"18}print("Objects created")# 6. 查看创建对象后的内存变化print(f"Free heap after create: {gc.mem_free()} bytes")print(f"Allocated heap after create: {gc.mem_alloc()} bytes")# 7. 切断引用,让对象成为垃圾(堆中对象无引用指向)obj1 = Noneobj2 = Noneprint("References cut, objects become garbage")# 8. 查看切断引用后的内存(未GC,内存未释放)print(f"Free heap before collect: {gc.mem_free()} bytes")print(f"Allocated heap before collect: {gc.mem_alloc()} bytes")# 9. 手动触发GC,清理垃圾对象# mpy中部分版本无返回值,故移除接收变量gc.collect()  print("Garbage collection executed")# 10. 查看GC后的内存变化(垃圾被清理,空闲内存增加)print(f"Free heap after collect: {gc.mem_free()} bytes")print(f"Allocated heap after collect: {gc.mem_alloc()} bytes")# 11. 演示循环引用的垃圾回收(引用计数法无法处理,需gc.collect())a = []b = []# a引用b, b引用a,形成循环引用a.append(b)  b.append(a) print("Circular reference objects created")# 12. 查看创建循环引用对象后的内存print(f"Free heap after circular ref: {gc.mem_free()} bytes")print(f"Allocated heap after circular ref: {gc.mem_alloc()} bytes")# 13. 切断外部引用,此时a和b互相引用,引用计数不为0a = Noneb = Noneprint("External references cut (circular ref remains)")# 14. 手动触发GC,清理循环引用的垃圾gc.collect()print("Garbage collection for circular ref executed")# 15. 查看清理循环引用后的内存print(f"Free heap after circular collect: {gc.mem_free()} bytes")print(f"Allocated heap after circular collect: {gc.mem_alloc()} bytes")# 16. 恢复自动GC,并重置阈值为默认(-1表示禁用阈值)gc.threshold(-1)print(f"Reset GC threshold: {gc.threshold()}")gc.enable()print(gc.isenabled())

运行终端,输出如下:整体流程如下图所示:内存变化如下表所示:

我们也可以使用 micropython.mem_info(1) 方法查看堆利用率表:

这是 MicroPython 的内存信息详细输出,用于查看栈和堆的整体状态,是分析内存的基础:

stack:516outof7936GC: total:233024,used:7168,free:225856No. of 1-blocks:96,2-blocks:26,max blk sz:64,max free sz:14075...(内存布局省略)
  • stack: 516 out of 7936 :栈内存已使用 516 字节,总大小 7936 字节。栈内存用于存储局部变量、函数调用上下文,这里栈使用量很小,处于安全状态。

  • GC: total: 233024, used: 7168, free: 225856:堆内存的核心统计(单位:字节):

    • total
      :堆内存总大小(233024 字节)。
    • used
      :当前已分配的堆内存(7168 字节),即程序中对象占用的堆空间。
    • free
      :当前空闲的堆内存(225856 字节),可用于分配新对象。
  • 块信息(1-blocks/2-blocks 等):MicroPython 的堆内存以「块」为单位分配,这里显示了不同大小块的数量、最大块大小、最大空闲块大小,反映了堆的碎片化程度。

  • 内存布局:以字符形式展示堆内存的使用状态(如 h 表示已用块、= 表示空闲块、D/B/S 是特殊标记),后续的 219 lines all free 表示大部分堆内存都是空闲的。

参考资料

https://docs.micropython.org/en/latest/reference/index.html

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 15:52:22 HTTP/2.0 GET : https://f.mffb.com.cn/a/510763.html
  2. 运行时间 : 0.368194s [ 吞吐率:2.72req/s ] 内存消耗:4,595.12kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=9f870a98bc3c66033f61b140859a16bc
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001048s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.002144s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.001955s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.016839s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001524s ]
  6. SELECT * FROM `set` [ RunTime:0.020692s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001739s ]
  8. SELECT * FROM `article` WHERE `id` = 510763 LIMIT 1 [ RunTime:0.026603s ]
  9. UPDATE `article` SET `lasttime` = 1787298742 WHERE `id` = 510763 [ RunTime:0.015323s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.000688s ]
  11. SELECT * FROM `article` WHERE `id` < 510763 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001164s ]
  12. SELECT * FROM `article` WHERE `id` > 510763 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.042785s ]
  13. SELECT * FROM `article` WHERE `id` < 510763 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.010173s ]
  14. SELECT * FROM `article` WHERE `id` < 510763 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.026948s ]
  15. SELECT * FROM `article` WHERE `id` < 510763 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.026454s ]
0.372462s