jiejieTop / mqttclient

A high-performance, high-stability, cross-platform MQTT client, developed based on the socket API, can be used on embedded devices (FreeRTOS / LiteOS / RT-Thread / TencentOS tiny), Linux, Windows, Mac, with a very concise The API interface realizes the quality of service of QOS2 with very few resources, and seamlessly connects the mbedtls encryption library.
Apache License 2.0
703 stars 256 forks source link

mqttclient连接上server后,断开网络, mqttclient会尝试重连,每次重连就会出现内存泄漏 #80

Closed henerywang closed 1 year ago

henerywang commented 1 year ago

![Uploading mem_leak.png…]()

wuhaogs commented 1 year ago

是存在这个问题。mqtt_yield_thread线程创建时,调用platform_memory_alloc分配了96B,mqtt_yield_thread退出时,只是设置了分离线程,线程ID资源可以释放,但是platform_thread_t资源并未释放。我建议这样修复:linux版本中,platform_thread_destroy接口,释放mqtt_yield_thread线程管理资源。 void platform_thread_destroy(platform_thread_t* thread) { if (NULL != thread) { pthread_detach(thread->thread); platform_memory_free(thread); //add }
}

wuhaogs commented 1 year ago

这样修复后,我发现还是存在问题,我正在尝试能否关闭重试逻辑。

wuhaogs commented 1 year ago

一旦断网 mqtt_keep_alive接口中,调用network_release接口释放连接,此时n->socket无效, 所以并未调用network_disconnect释放连接,这样使得nettype_tls_params堆空间没有释放,并且此处复位了network_t n,这样n->channel变为0, 所以即使组件调用者主动断开连接,也无法释放此处空间。 目前删除下列memset 可以解决断网产生的内存泄漏 void network_release(network_t* n) { DBG_PRINT("[enter]network_release,n->socket=%d\n",n->socket);

if (n->socket >= 0)
    network_disconnect(n);

//memset(n, 0, sizeof(network_t)); //wuhaodel   LEAK MEM

}

henerywang commented 1 year ago

void platform_thread_destroy(platform_thread_t thread) { if (NULL != thread) { pthread_detach(thread->thread); platform_memory_free(thread); //add } } void network_release(network_t n) { DBG_PRINT("[enter]network_release,n->socket=%d\n",n->socket);

if (n->socket >= 0) network_disconnect(n);

//memset(n, 0, sizeof(network_t)); //wuhaodel LEAK MEM }

这样修正后,问题还是存在,请帮忙再check check @wuhaogs

wuhaogs commented 1 year ago

我目前通过注释源码中的重试机制,外部通过销毁客户端重建的方式进行重试。 通过virgrind内存检测,没发生泄漏问题。 // 1.注释源码中的重试流程 static int mqtt_try_reconnect(mqtt_client_t* c): rc = mqtt_try_do_reconnect(c); -> rc = MQTT_NOT_CONNECT_ERROR;

// 2.调用者实现销毁mqtt客户端接口 int32 mbed_exitMqttClient() { MQTT_CLIENT_HANDLE clientID = (MQTT_CLIENT_HANDLE)getMqttClientHandle();

if (!clientID)
{
    return ERROR;
}

DBG_PRINT("[enter]exit MqttClient,state=%u\n", clientID->mqtt_client_state);

// 释放由调用mqtt_set_will_options产生的堆空间
if (clientID->mqtt_will_options)
{
    DBG_PRINT("[mqtt exit]mqtt_set_will_options(%p) free OK\n",clientID->mqtt_will_options);
    platform_memory_free(clientID->mqtt_will_options);
}

if (1 == clientID->mqtt_client_state || 2 == clientID->mqtt_client_state)
{
    DBG_PRINT("[mqtt exit]mqtt_disconnect\n");
    if (SUCCESS == mqtt_disconnect(clientID))
    {
        DBG_PRINT("[mqtt exit]mqtt_disconnect OK\n");
    }

    while (-1 != clientID->mqtt_client_state)
    {
        adlBlockWait(2, MILLISECOND);
    }
}

DBG_PRINT("[mqtt exit]mqtt_release,state =%d\n",clientID->mqtt_client_state);

if (SUCCESS == mqtt_release(clientID))
{
    DBG_PRINT("[mqtt exit]mqtt_release OK\n");
}

DBG_PRINT("[mqtt exit]call mqtt free(%p) OK\n", clientID);

platform_memory_free(clientID);

clientID = NULL;

setMqttClientHandle(NULL);

DBG_PRINT("[mqtt exit]destroy MqttClient\n\n");

return ETOK;

}

wuhaogs commented 1 year ago

另外关于platform_thread_destroy内存泄漏问题,最新仓库中代码已经修复。