You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用open62541读取OPCUA服务器数据时出现内存泄漏问题

问题分析与修复方案

你的内存泄漏问题核心是未正确释放open62541服务调用返回的响应资源,内存持续累积最终触发系统OOM杀死进程。

具体问题点

在readOPCData函数中,调用UA_Client_Service_read获取UA_ReadResponse后,没有调用open62541提供的清理函数释放该响应结构体内部的动态分配内存。open62541的所有服务响应结构体(如UA_ReadResponse)都包含动态分配的字段(比如results数组),必须显式调用对应的_delete函数释放。

修复代码

修改readOPCData函数,在返回前添加响应清理逻辑:

int readOPCData(struct ClientOPCEndpointInfo* *clientInfos, char *timestamp)
{
    UA_ReadValueId ids[nodeCount];
    
    for (int i = 0; i < nodeCount; i++)
    {
        UA_ReadValueId_init(&ids[i]);
        ids[i].attributeId = UA_ATTRIBUTEID_VALUE;
        ids[i].nodeId = clientNodes[i];
    }

    UA_ReadRequest_init(&request);
    request.nodesToRead = ids;
    request.nodesToReadSize = nodeCount;

    UA_ReadResponse response = UA_Client_Service_read(client, request);

    if (response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
    {
        logError("Error while reading OPC data from OPC server!", true);
        // 出错时也要清理响应
        UA_ReadResponse_delete(&response);
        return 1;
    }

    UA_DateTime responseDateTime = response.responseHeader.timestamp;
    UA_Int64 responseTimestamp = UA_DateTime_toUnixTime(responseDateTime);
    sprintf(timestamp, "%li", responseTimestamp);

    for (int i = 0; i < nodeCount; i++)
    {
        UA_Variant *variant = &response.results[i].value;

        if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_DOUBLE]))
        {
            UA_Double value = *(UA_Double*)variant->data;
            *clientInfos[i]->value = (double)value;
        }
        else if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_FLOAT]))
        {
            UA_Float value = *(UA_Float*)variant->data;
            *clientInfos[i]->value = (double)value;
        }
        else if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_UINT32]))
        {
            UA_UInt32 value = *(UA_UInt32*)variant->data;
            *clientInfos[i]->value = (double)value;
        }
        else if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_BOOLEAN]))
        {
            UA_Boolean value = *(UA_Boolean*)variant->data;
            *clientInfos[i]->value = (double)value;
        }
    }

    // 释放响应资源
    UA_ReadResponse_delete(&response);
    // 清理栈上的request结构体内部资源
    UA_ReadRequest_clear(&request);

    return 0;
}

额外检查点

  1. 客户端销毁:在程序退出时,务必调用UA_Client_delete(client);释放客户端实例的所有资源,避免遗漏内存泄漏。
  2. 结构体初始化与清理配对:对于栈上初始化的结构体(如UA_ReadRequest),使用_init初始化后,必须用_clear清理内部动态资源;对于动态分配的结构体,用_new创建后用_delete销毁。

验证

修复后重新用Valgrind检测,确认该内存泄漏记录消失。如果仍有其他泄漏,再排查是否有其他未配对的资源操作。

内容的提问来源于stack exchange,提问作者Sebastian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:03:17