解决libcurl内存泄露的问题

 

情景是一个程序一直执行Post,通过http协议上传数据。

一般的办法是:

先curl_easy_init();

之后再curl_easy_perform(curl);

最后 curl_easy_cleanup(curl); 

但是这种方法是存在内存泄露的。参见https://stackoverflow.com/questions/11494950/memory-leak-from-curl-library

示例:

#include <iostream>
#include "curl/curl.h"
int main(void)
{
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.del.icio.us/dt");
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
        curl_easy_setopt(curl, CURLOPT_CAINFO, "C:\\Users\\bryan\\GeoTrustGlobalCA.crt");
        /* Perform the request, res will get the return code */ 
        res = curl_easy_perform(curl);
        /* Check for errors */ 
        if(res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

        /* always cleanup */ 
        curl_easy_cleanup(curl);
    }
    return 0;
}

解决办法是执行curl_global_cleanup()

但是考虑到如果使用http长连接的话,可能会效率更高,因此,在执行上传部分添加了时间判断逻辑,如果超过1分钟就执行curl_global_cleanup(),然后重新新建一个curl对象,否则就使用原来的curl对象。

经过测试,执行curl_global_cleanup()后是没有内存泄露的。

#ifndef HTTPCLIENT_HPP
#define HTTPCLIENT_HPP

#include <chrono>

#define CURL_STATICLIB   //静态链接
#include <curl/curl.h>
#include <qdebug.h>

class HttpClient
{

private:  // 不允许复制
     HttpClient( const HttpClient& );
     const HttpClient& operator=( const HttpClient& );

public:
    HttpClient()
    {
        curl_global_init(CURL_GLOBAL_WIN32);
        m_curl = curl_easy_init();//init()
		m_oldTimePoint = std::chrono::system_clock::now();
    }

    ~HttpClient()
    {
        curl_easy_cleanup(m_curl);
        curl_global_cleanup();
    }

    bool send(const std::string &strUrl,std::string &jsonStr)
    {
        string response;
        //string url = "http://127.0.0.1:8080/";


		std::chrono::system_clock::time_point nowTimePoint = std::chrono::system_clock::now();

		std::chrono::duration<double, std::milli> tm = nowTimePoint - m_oldTimePoint;	// 毫秒
		
		if (tm.count() > 60 * 1000)//如果超过60秒就释放资源,重新生成url对象
		{
			curl_easy_cleanup(m_curl);
			curl_global_cleanup();
			m_curl = curl_easy_init();
			m_oldTimePoint = nowTimePoint;
		}


        int httpCode = httpPost(strUrl, jsonStr, response);
        qDebug() << "retCode:" << httpCode;

        if (httpCode == CURLE_OK)//CURLE_OK=0
            return true;
        else
            return false;
    }

private:

    CURL* m_curl;
	std::chrono::system_clock::time_point m_oldTimePoint;

    int httpPost(const std::string & strUrl, const std::string & strPost, std::string & strResponse)
    {
        CURLcode res;
        CURL* curl = m_curl;// curl_easy_init();
        if (NULL == curl)
        {
            curl = curl_easy_init();
           // return CURLE_FAILED_INIT;
        }

        if ( false )//用于调试的设置
        {
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
            curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
        }

        curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
        curl_easy_setopt(curl, CURLOPT_POST, 1);//设置为非0表示本次操作为POST
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 3000);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300);

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);  //支持服务器跳转
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);  // enable TCP keep-alive for this transfer
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);	// keep-alive idle time to 120 seconds
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);	// interval time between keep-alive probes: 60 seconds

        struct curl_slist* headers = NULL;
        headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        res = curl_easy_perform(curl);

        curl_slist_free_all(headers);//清理headers,防止内存泄漏
        //curl_easy_cleanup(curl);
        return res;
    }

    static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)//curl调试
    {
        if (itype == CURLINFO_TEXT)
        {
            qDebug() << "[TEXT]"<< pData;//logOutput(string(pData));//printf("[TEXT]%s\n", pData);
        }
        else if (itype == CURLINFO_HEADER_IN)
        {
            qDebug() << "[HEADER_IN]" << pData; // printf("[HEADER_IN]%s\n", pData);
        }
        else if (itype == CURLINFO_HEADER_OUT)
        {
            qDebug() << "[HEADER_OUT]" << pData; //printf("[HEADER_OUT]%s\n", pData);
        }
        else if (itype == CURLINFO_DATA_IN)
        {
            qDebug() << "[DATA_IN]" << pData; //printf("[DATA_IN]%s\n", pData);
        }
        else if (itype == CURLINFO_DATA_OUT)
        {
            qDebug() << "[DATA_OUT]" << pData; //printf("[DATA_OUT]%s\n", pData);
        }
        return 0;
    }

    static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
    {
        std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
        if (NULL == str || NULL == buffer)
        {
            return -1;
        }

        char* pData = (char*)buffer;
        str->append(pData, size * nmemb);
        return nmemb;
    }

};


#endif // HTTPCLIENT_HPP

 

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
在使用libcurl时,确保正确管理内存是非常重要的,以避免内存泄漏。下面是一些可以帮助您避免内存泄漏的最佳实践: 1. 初始化和清理:在使用libcurl之前,调用`curl_global_init`函数进行全局初始化,并在使用完毕后,调用`curl_global_cleanup`函数进行全局清理。 2. curl_easy_cleanup:在每次使用完curl句柄后,调用`curl_easy_cleanup`函数进行清理。这将释放与句柄关联的资源,包括内部分配的内存。 3. curl_slist_free_all:当使用`curl_slist`结构来存储HTTP头部时,使用`curl_slist_free_all`函数释放该结构和其关联的内存。 4. CURLOPT_WRITEFUNCTION:如果您使用`CURLOPT_WRITEFUNCTION`选项设置了写入回调函数,确保在回调函数中适当处理接收到的数据。如果您使用了动态分配的缓冲区来存储数据,请在使用完数据后释放缓冲区。 5. CURLOPT_READFUNCTION:类似地,如果您使用`CURLOPT_READFUNCTION`选项设置了读取回调函数,确保在读取回调函数中管理内存,并在需要时释放相关的资源。 6. CURLOPT_POSTFIELDS:如果您使用`CURLOPT_POSTFIELDS`选项来提供POST请求的数据,请确保您在请求完成后释放相关的资源。 7. 错误处理:在使用libcurl时,检查每个libcurl函数的返回值(通常是`CURLcode`类型),以确保操作成功。对于失败的操作,请适当处理错误,并释放相应的资源。 8. 内存检查工具:使用内存检查工具(如Valgrind)来帮助检测和调试内存泄漏问题。 请注意,上述仅是一些常见的内存管理建议,实际情况可能因您的具体代码和需求而有所不同。确保仔细阅读libcurl的文档,并根据您的代码进行适当的内存管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路边闲人2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值