四大核心功能实战剖析LuatOS 内存管理
在嵌入式开发中,内存管理是决定系统稳定性和性能的关键因素。LuatOS 作为一款面向物联网设备的轻量级实时操作系统,其内存管理机制设计精巧,但如果不深入了解各功能模块的内存使用特点,很容易在实际开发中遇到内存泄漏、碎片化或溢出等问题。
在嵌入式开发中,内存管理是决定系统稳定性和性能的关键因素。LuatOS 作为一款面向物联网设备的轻量级实时操作系统,其内存管理机制设计精巧,但如果不深入了解各功能模块的内存使用特点,很容易在实际开发中遇到内存泄漏、碎片化或溢出等问题。
本文将通过zbuff、UART、MQTT、Socket四大核心功能的实战代码,结合Luatools内存监控工具,深入剖析LuatOS的内存分配机制。每个功能模块我们都将:
- 展示完整示例代码 - 提供可直接运行的Lua代码
- 实时监控内存变化 - 使用
rtos.meminfo()跟踪lua和sys内存 - 分析内存分配特点 - 揭示各功能的内存使用规律
- 总结最佳实践 - 提供具体的使用建议
一、zbuff功能内存使用分析
zbuff是LuatOS中用于直接操作二进制内存数据的库,内存组成:
-
Lua对象元数据(小,在Lua内存);
-
C层数据块(大,如存在PSRAM则在psram中进行申请,如不存在或失败则在SRAM上的sys中进行申请)。
1.1 示例代码
的 sys 中进行申请)。
-- zbuff 内存使用示例_
log.info("初始内存状态:")
log.info("lua:", rtos.meminfo("lua"))
--对于780EHM来说,sys分区和psram分区都在PSRAM上,实际是同一个东西, 数据完全一样,所以只看sys内存即可。
--对于PSRAM以及SRAM都存在的模组,如存在PSRAM则在psram中进行申请,如不存在或失败则在SRAM上的sys中进行申请,
--所以需要根据具体模组来打印sys分区以及psram分区_
log.info("sys:", rtos.meminfo("sys"))
log.info("psram:", rtos.meminfo("psram"))
-- 1. buff_auto这个Lua对象是从lua内存区域分配的,这个对象指向的1MB字节的内存是从sys内存区域分配的
local buff_auto = zbuff.create(1024 * 1024) -- 申请 1MB 内存
local buff_with_data = zbuff.create(512 * 1024, "initial data") -- 申请 512KB 带初始数据的 zbuff
log.info("创建 zbuff 后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
1.2 内存分析
通过官方调试工具Luatools的内存监控功能,可查看内存数据和曲线图。
新朋友可查看Luatools下载和详细使用文档:
1.3 关键结论
1)内存分配特点:**zbuff通过分离Lua元数据(小,存储对象信息)和C层数据块(大,存储实际数据),实现了高效的内存管理:
-
大内存块在sys分区/psram分区中分配,不占用Lua内存;
-
支持手动释放数据块,避免内存泄漏;
-
创建大内存时自动触发GC,优化内存使用。
2)使用建议:**处理大块二进制数据(如网络下载、图像解码、文件读写)时,优先使用zbuff。
二、UART功能内存使用分析
UART是嵌入式系统常用通信接口,内存组成:
-
lua配置信息(小);
-
sys发送/接收缓冲区(核心)。
2.1 示例代码
-- UART 内存使用示例
log.info("初始内存状态:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
local uart_id = 1 -- UART 端口号
-- 1. 初始化 UART
-- 发送和接收缓冲区在 sys 内存中分配
local setup_result = uart.setup(uart_id, -- 串口 ID
115200, -- 波特率
8, -- 数据位
1, -- 停止位
uart.NONE, -- 校验位(uart.NONE/uart.EVEN/uart.ODD)
uart.LSB, -- 大小端(uart.LSB/uart.MSB)
4096 -- 接收缓冲区大小:4KB,发送缓冲区大小固定
)
log.info("初始化 UART 后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 2. 发送数据(字符串方式)
-- 数据首先被复制到 UART 发送缓冲区(sys 内存)
-- 然后由硬件自动发送
local send_data = string.rep("test_data_", 100) -- 约 900 字节的数据
log.info("发送数据前:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 注册发送完成回调
local function uart_sent_callback(id)
log.info("UART 发送完成回调:", id)
-- 发送完成后,发送缓冲区会自动释放
log.info("发送完成后内存状态:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
end
-- 注册发送完成事件回调
uart.on(uart_id, "sent", uart_sent_callback)
-- 数据复制到发送缓冲区的操作在 uart.write() 调用中执行
-- 这一步会将 send_data 字符串复制到 UART 发送缓冲区(sys 内存)
uart.write(uart_id, send_data)
log.info("调用 uart.write() 后(数据已复制到发送缓冲区):")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 等待发送完成回调(实际使用中应在回调中处理,这里为演示暂停)
sys.wait(1000) -- 等待发送完成
-- 3. 发送数据(zbuff 方式)
-- 使用 zbuff 发送数据,减少内存拷贝
local txbuff = zbuff.create(1024)
log.info("创建发送 zbuff 后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 向 zbuff 写入数据
local write_len = txbuff:write("Hello from zbuff!")
log.info("使用 zbuff 发送数据:")
-- 使用 uart.tx() 发送 zbuff 数据
-- 此方式直接使用 zbuff 数据,减少一次内存拷贝
local tx_result = uart.tx(uart_id, txbuff)
log.info("调用 uart.tx() 后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 等待发送完成回调
sys.wait(1000) -- 等待发送完成
log.info("zbuff 发送完成后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 4. 接收数据回调
-- 接收数据存储在 UART 接收缓冲区(sys 内存)
local rxbuff = zbuff.create(4096)
log.info("创建接收 zbuff 后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
local function uart_receive_callback(id, len)
log.info("UART 接收数据回调,可用长度:", len)
-- 从 UART 接收缓冲区读取数据到 zbuff
local read_len = uart.rx(id, rxbuff)
if read_len > 0 then
log.info("实际读取长度:", read_len)
log.info("接收数据:", rxbuff:toStr(0, read_len))
-- 接收数据后,UART 接收缓冲区会自动清空
log.info("接收数据后内存状态:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 重置 zbuff 指针,准备下次接收
rxbuff:seek(0)
end
end
-- 注册接收回调
uart.on(uart_id, "receive", uart_receive_callback)
-- 5. 释放资源
-- 释放 zbuff 资源
txbuff:free()
rxbuff:free()
log.info("释放 zbuff 后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 6. 关闭串口
-- 使用 uart.close() 函数关闭串口,释放串口相关资源
uart.close(uart_id)
log.info("关闭串口后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 注意:uart.close() 函数用于关闭串口,释放相关资源
-- 调用后串口将不再可用,需要重新调用 uart.setup() 才能再次使用
2.2 内存分析
通过官方调试工具Luatools的内存监控功能,可查看内存数据和曲线图。

2.3 关键结论
1)内存分配特点:**UART主要使用sys内存作为收发缓冲区,lua内存仅存储配置对象和回调函数。
发送方式对比:
-
字符串发送:数据需复制到发送缓冲区,有额外内存拷贝;
-
zbuff发送:直接使用zbuff数据,无额外内存拷贝,效率更高。
资源管理:
-
发送完成后,发送缓冲区自动释放;
-
调用zbuff:free() 释放zbuff数据块;
-
调用uart.close() 释放串口相关资源。
2)使用建议:**大数据发送优先使用zbuff方式,减少内存拷贝和碎片。
三、MQTT功能内存使用分析
MQTT是物联网设备常用的轻量级通信协议,在LuatOS中MQTT客户端的内存使用涉及lua和sys内存分配:
-
lua内存: 主要存储客户端对象、配置信息、订阅信息和临时消息对象,占用较小但管理核心逻辑;
-
sys内存: 主要存储连接和收发缓冲区,是内存使用的核心部分,占用较大且随消息大小动态变化。
3.1 示例代码
-- MQTT 内存使用示例
log.info("初始内存状态:")
log.info("lua:", rtos.meminfo("lua")) -- 记录Lua虚拟机内存使用
log.info("sys:", rtos.meminfo("sys")) -- 记录系统内存使用
-- 配置 MQTT 服务器信息
local SERVER_ADDR = "lbsmqtt.airm2m.com"
local SERVER_PORT = 1884
local USERNAME = "test"
local PASSWORD = "test"
local CLIENT_ID = "luatos_test_device"
-- 定义 MQTT 客户端回调函数
local function mqtt_client_cb(mqtt_client, event, data, payload, metas)
log.info("MQTT 事件:", event, data, payload and #payload or "nil")
-- 连接成功事件
if event == "conack" then
log.info("MQTT 连接成功")
-- 连接成功后可以订阅主题
-- 内存影响:
-- - lua内存:增加约592B,存储订阅信息
-- - sys内存:基本不变
mqtt_client:subscribe("device/commands", 0)
-- 对应内存分析:步骤 6,订阅主题后
log.info("订阅主题后内存:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
end
-- 接收到消息事件
if event == "recv" then
log.info("MQTT 接收消息:", data, #payload, "字节")
-- 内存影响:接收到消息时的临时内存使用
-- 对应内存分析:接收消息后,检查消息接收的内存变化
log.info("接收消息后内存:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 对于大消息,可以使用 zbuff 处理
-- 内存影响:创建临时zbuff对象,处理完成后释放
if #payload > 1024 then -- 大于 1KB 的消息
local buff = zbuff.create(#payload) -- 创建对应大小的zbuff
buff:write(payload) -- 写入数据
-- 处理数据...
buff:free() -- 释放zbuff数据块
end
end
end
-- MQTT 客户端需要在 task 中运行
local function mqtt_test_task()
-- 1. 创建 MQTT 客户端
-- 参数:nil, 服务器地址, 服务器端口
-- 内存影响:
-- - lua内存:增加约38120B,存储客户端对象和内部数据结构
-- - sys内存:增加约3848B,分配基础结构
local mqtt_client = mqtt.create(nil, SERVER_ADDR, SERVER_PORT)
-- 对应内存分析:步骤 3,创建 MQTT 客户端后
log.info("创建 MQTT 客户端后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 2. 配置认证信息
-- 内存影响:
-- - lua内存:增加约264B,存储认证配置
-- - sys内存:基本不变
mqtt_client:auth(CLIENT_ID, USERNAME, PASSWORD, true)
-- 对应内存分析:步骤 4,配置认证信息后
log.info("配置认证信息后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 3. 注册事件回调
-- 内存影响:无显著内存变化,仅注册回调函数
mqtt_client:on(mqtt_client_cb)
-- 4. 设置 keepalive
-- 内存影响:无显著内存变化,仅设置参数
mqtt_client:keepalive(30)
-- 5. 连接 MQTT 服务器
-- 内存影响:
-- - lua内存:增加约160B,存储连接状态
-- - sys内存:增加约33204B,分配连接和收发缓冲区
local connect_result = mqtt_client:connect()
-- 对应内存分析:步骤 5,连接 MQTT 服务器后
log.info("连接 MQTT 服务器后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 等待连接成功(最多10秒)
-- 对应内存分析:步骤 2,网络连接就绪,无明显内存变化
local connected = false
local start_time = os.time()
while not connected and os.time() - start_time < 10 do
sys.wait(1000)
-- 检查连接状态(实际应用中通过事件判断)
connected = true -- 简化示例,实际应通过事件回调判断
end
if connected then
-- 6. 发布小消息
-- 内存影响:
-- - lua内存:增加约376B,存储消息对象
-- - sys内存:减少约472B,可能是临时对象释放
local small_msg = "{\"temp\":25.5,\"humidity\":60}" -- 约 30 字节
-- 对应内存分析:步骤 7,发布小消息前
log.info("发布小消息前:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 内存影响:
-- - lua内存:增加约176B,消息发送相关结构
-- - sys内存:增加约380B,消息发送缓冲区
local publish_result = mqtt_client:publish("sensor/data", small_msg, 0)
-- 对应内存分析:步骤 8,发布小消息后
log.info("发布小消息后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 7. 发布大消息
-- 内存影响:
-- - lua内存:增加约10328B,存储大消息对象
-- - sys内存:基本不变
local large_msg = string.rep("0123456789", 1000) -- 约 10KB 数据
-- 对应内存分析:步骤 9,发布大消息前
log.info("发布大消息前:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 内存影响:
-- - lua内存:增加约208B,消息发送相关结构
-- - sys内存:增加约12300B,大消息发送缓冲区
local publish_result = mqtt_client:publish("sensor/large_data", large_msg, 0)
-- 对应内存分析:步骤 10,发布大消息后
log.info("发布大消息后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 运行一段时间
sys.wait(5000)
end
-- 8. 断开连接
-- 内存影响:
-- - lua内存:增加约376B,断开连接相关操作
-- - sys内存:减少约12404B,释放连接相关资源
mqtt_client:disconnect()
-- 对应内存分析:步骤 11,断开 MQTT 连接后
log.info("断开 MQTT 连接后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
-- 9. 关闭客户端并释放资源
-- 内存影响:关闭客户端,准备释放资源
mqtt_client:close()
mqtt_client = nil -- 断开引用,等待GC回收
-- 重复执行多次垃圾回收操作,每次间隔1秒
-- 目的是彻底释放MQTT客户端占用的资源,确保内存完全回收
-- 内存影响:
-- - lua内存:减少约49272B,客户端对象和相关结构完全释放
-- - sys内存:减少约33436B,释放所有 MQTT 相关资源
-- 多次执行垃圾回收并间隔等待,确保:
-- 1. Lua的垃圾回收器采用增量式标记-清除算法,多次调用 collectgarbage("collect") 是为了确保更彻底地回收垃圾
-- 2. mqtt是异步操作,使用非阻塞函数和事件回调机制来处理网络操作。某些资源的释放可能依赖于异步操作,需要等待系统完成相关处理
-- 3. 多次回收有助于更有效地整理内存碎片,提高内存使用效率
for i = 1, 5 do
collectgarbage("collect") -- 执行垃圾回收
sys.wait(1000) -- 等待1秒,让系统有时间处理垃圾回收
end
-- 对应内存分析:步骤 12,关闭客户端并多次 GC 后
-- 最终状态:
-- - lua内存:约40248B(接近初始状态的38920B)
-- - sys内存:约108068B(接近初始状态的104760B)
log.info("关闭客户端并 GC 后:")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
log.info("MQTT 客户端资源已释放")
end
-- 创建并启动 MQTT 测试任务
sys.taskInit(mqtt_test_task)
3.2 内存分析
通过官方调试工具Luatools的内存监控功能,可查看内存数据和曲线图。
3.3 关键结论
MQTT客户端内存使用涉及lua和sys内存。
1)内存分配特点:
-
lua内存:主要存储客户端对象、配置信息、订阅信息和临时消息对象;
-
sys内存:主要存储连接和收发缓冲区,是内存使用的核心部分。
内存使用特点:
-
创建客户端:lua内存增长明显(约38KB);
-
连接服务器:sys内存增长明显(约33KB);
-
发布消息:大消息会在lua内存中创建临时对象(约10KB),并在 sys内存中分配发送缓冲区;
-
多次GC:通过多次执行collectgarbage(“collect”),内存可几乎完全恢复到初始状态。
2)使用建议:
大消息发布时注意内存使用峰值;不再使用的MQTT客户端应及时调用close() 并设置为nil;执行多次GC操作以确保内存完全回收。
四、Socket功能内存使用分析
Socket是网络通信的基础接口,在LuatOS中Socket的内存使用主要涉及sys内存,用于存储发送和接收缓冲区;同时也会使用lua内存存储Socket对象和配置。
LuatOS的socket库是异步非阻塞API。
4.1 示例代码
-- Socket内存使用情况完整演示
-- 加载libnet库
local libnet = require "libnet"
-- 配置
local SERVER_ADDR = "112.125.89.8"
local SERVER_PORT = 33768
local TASK_NAME = "socket_mem_demo"
-- 内存记录函数
local function log_memory_info(step)
log.info("=== " .. step .. " ===")
log.info("lua:", rtos.meminfo("lua"))
log.info("sys:", rtos.meminfo("sys"))
end
-- 消息回调函数(libnet需要)
local function mem_demo_callback(msg)
log.info("mem_demo回调")
end
-- 主任务函数
local function socket_memory_task()
-- 等待网络就绪
sys.waitUntil("IP_READY", 30000)
-- 记录初始内存
-- 对应内存分析:初始状态,记录系统启动后的内存基线
log_memory_info("初始状态")
-- 1. 创建socket
-- 内存影响:
-- - lua内存:增加约392B,存储socket对象和相关配置信息
-- - sys内存:增加约108B,分配socket控制块和基础结构
local socket_client = socket.create(nil, TASK_NAME)
if not socket_client then
log.error("创建socket失败")
sys.cleanMsg(TASK_NAME)
sys.taskDel(TASK_NAME)
return
end
-- 对应内存分析:创建socket后,检查socket对象分配的内存
log_memory_info("创建socket后")
-- 2. 配置socket
-- 内存影响:配置socket参数,无显著内存变化
if not socket.config(socket_client) then
log.error("配置socket失败")
socket.release(socket_client)
sys.cleanMsg(TASK_NAME)
sys.taskDel(TASK_NAME)
return
end
-- 3. 创建接收缓冲区
-- 内存影响:
-- - lua内存:增加约248B,存储zbuff对象元数据
-- - sys内存:增加约1024B,分配1KB的实际接收缓冲区
local rx_buff = zbuff.create(1024)
-- 对应内存分析:创建缓冲区后,检查1KB缓冲区的内存分配
log_memory_info("创建缓冲区后")
-- 4. 连接服务器
-- 内存影响:
-- - lua内存:增加约1032B,存储连接状态、服务器地址信息
-- - sys内存:减少约284B,内核优化临时缓冲区使用
log.info("正在连接服务器...")
local connect_result = libnet.connect(TASK_NAME, 10000, socket_client, SERVER_ADDR, SERVER_PORT)
if connect_result then
log.info("连接成功")
-- 对应内存分析:连接服务器后,检查连接过程的内存变化
log_memory_info("连接服务器后")
-- 5. 发送数据
-- 内存影响:
-- - lua内存:增加约816B,存储临时发送数据对象和发送状态
-- - sys内存:减少约80B,发送缓冲区数据被网络层处理后释放
local test_data = "内存测试数据 " .. os.time()
local send_result = libnet.tx(TASK_NAME, 5000, socket_client, test_data)
if send_result then
log.info("发送成功:", test_data)
-- 对应内存分析:发送数据后,检查数据发送过程的内存变化
log_memory_info("发送数据后")
else
log.warn("发送失败")
end
-- 6. 等待并接收数据
-- 内存影响:
-- - lua内存:增加约544B,存储接收到的数据对象和接收状态
-- - sys内存:增加约148B,内核处理接收到的数据时的临时缓冲区使用
-- 等待5秒,期间持续检查数据,5秒后无论是否收到数据都继续执行
local wait_start = os.time()
local has_received_data = false
while os.time() - wait_start < 5 do
-- 检查是否有数据
local rx_result = socket.rx(socket_client, rx_buff)
if rx_result then
if rx_buff:used() > 0 and not has_received_data then
log.info("recv data len", rx_buff:used())
-- 对应内存分析:接收数据后,检查数据接收过程的内存变化
log_memory_info("接收数据后")
has_received_data = true
-- 收到数据后不立即跳出循环,继续等待剩余时间
end
else
log.error("socket.rx失败")
-- socket.rx失败也不立即跳出循环,继续等待剩余时间
end
sys.wait(200)
end
log.info("等待5秒接收数据完成")
-- 7. 关闭连接
-- 内存影响:
-- - lua内存:增加约4768B,连接关闭过程中产生的临时对象和状态信息
-- - sys内存:增加约188B,TCP四次挥手过程中的状态管理开销
log.info("正在关闭连接...")
libnet.close(TASK_NAME, 5000, socket_client)
-- 对应内存分析:关闭连接后,检查连接关闭过程的内存变化
log_memory_info("关闭连接后")
else
log.error("连接失败")
end
-- 8. 释放资源
-- 内存影响:
-- - lua内存:增加约168B,资源释放过程中的临时操作
-- - sys内存:减少约1136B,释放socket控制块和1KB接收缓冲区
if socket_client then
socket.release(socket_client) -- 释放socket控制块
socket_client = nil -- 断开引用,等待GC回收
end
if rx_buff then
rx_buff:free() -- 释放zbuff数据块
rx_buff = nil -- 断开引用,等待GC回收
end
-- 对应内存分析:释放资源后,检查资源释放的内存变化
log_memory_info("释放资源后")
-- 9. 强制垃圾回收
-- 重复执行多次垃圾回收操作,每次间隔1秒
-- 目的是彻底释放socket客户端占用的资源,确保内存完全回收
-- 内存影响:
-- - lua内存:减少约9344B,回收所有临时对象、socket对象、缓冲区对象等
-- - sys内存:减少约228B,内核清理剩余的socket相关资源
-- 多次执行垃圾回收并间隔等待,确保:
-- 1. Lua的垃圾回收器采用增量式标记-清除算法,多次调用 collectgarbage("collect") 是为了确保更彻底地回收垃圾
-- 2. socket是异步操作,使用非阻塞函数和事件回调机制来处理网络操作。某些资源的释放可能依赖于异步操作,需要等待系统完成相关处理
-- 3. 多次回收有助于更有效地整理内存碎片,提高内存使用效率
for i = 1, 5 do
collectgarbage("collect") -- 执行垃圾回收
sys.wait(1000) -- 等待1秒,让系统有时间处理垃圾回收
end
-- 对应内存分析:垃圾回收后,检查内存恢复情况
log_memory_info("垃圾回收后")
-- 10. 内存对比总结
-- 最终状态:
-- - lua内存:约42800B(接近初始状态的44176B)
-- - sys内存:约108052B(接近初始状态的108312B)
-- 结论:通过完整的资源释放和多次垃圾回收,内存基本恢复到初始状态
log.info("=== 内存演示完成 ===")
-- 清理task资源
sys.cleanMsg(TASK_NAME)
sys.taskDel(TASK_NAME)
end
-- 使用sys.taskInitEx创建任务(libnet需要)
sys.taskInitEx(socket_memory_task, TASK_NAME, mem_demo_callback)
4.2 内存分析
通过官方调试工具Luatools的内存监控功能,可查看内存数据和曲线图。
4.3 关键结论
1)内存分配特点
-
lua内存:主要用于存储对象和状态信息,波动较大;
-
sys内存:主要用于实际的缓冲区和内核结构,分配后相对稳定。
2)使用建议:
不再使用的MQTT客户端及时调用socket.release()释放socket资源;使用的zbuff缓冲区及时调用zbuff:free()释放缓冲区资源;lua层的内存须进行多次垃圾回收才能完全释放。
通过以上实战分析可以看出,不同功能的内存使用各有特点,但有一个共同原则:
大块数据用zbuff,异步资源释放要彻底,多次GC是关键。配合Luatools的内存监控工具,内存问题便无处遁形。
分享就到这里了
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)