Win32-API 的 WinHTTP 相关函数 有内存泄露??

CCDDzclxy 2013-07-11 01:19:50
RT
不知是否我的用法不对,或者哪里不规范,请帮忙指正。

环境 WinXP + VC6 。是控制台程序。
下面这段代码在运行较长时间后会有内存缓慢增长,不知是什么原因...故来求助。

#include <windows.h>
#include <stdio.h>

#include <string>
using namespace std;

#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")

#include <Wincrypt.h>
#pragma comment(lib, "Crypt32.lib")


WCHAR g_sAgentName[] = L"ZC Firm";
INTERNET_PORT m_wPort = INTERNET_DEFAULT_HTTPS_PORT;

// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

HINTERNET g_hSession = NULL;
HINTERNET g_hConnect = NULL;
HINTERNET g_hRequest = NULL;

int g_secureFlags = WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE;//WINHTTP_FLAG_ESCAPE_PERCENT |

// *** *** ***

void zcCrackUrl(WCHAR* _url);
URL_COMPONENTS g_uc = {0};
const DWORD BUF_LEN = 256;
WCHAR g_ucHost[BUF_LEN] = {0};
WCHAR g_ucPath[BUF_LEN] = {0};

char g_bufReadData[1024] = {0};


void ClearHandles();
void CALLBACK zcCallBack(
IN HINTERNET _hInternet,
IN DWORD_PTR _dwContext,
IN DWORD _dwInternetStatus,
IN LPVOID _lpvStatusInformation OPTIONAL,
IN DWORD _dwStatusInformationLength);



void zcTest()
{
ClearHandles(); // 关闭3个 HINTERNET 句柄

zcCrackUrl(L"https://passport.jd.com/new/login.aspx");

g_hSession = WinHttpOpen(g_sAgentName, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, WINHTTP_FLAG_ASYNC);
if (! g_hSession)
{
printf("Cannot open internet : %d\n", GetLastError());
return;
}

g_hConnect = WinHttpConnect(
g_hSession,
g_ucHost,
m_wPort,
0);
if (! g_hConnect)
{
printf("Cannot connect to internet : %d\n", GetLastError());
ClearHandles();
return;
}

g_hRequest = WinHttpOpenRequest(
g_hConnect,
L"HEAD",
g_ucPath,
NULL,
L"",
NULL,
g_secureFlags);
if (! g_hRequest)
{
printf("Cannot perform http request : %d\n", GetLastError());
ClearHandles();
return;
}
//*
// *** 不保持连接状态(每次请求完HEAD都断开)
DWORD dwOption = WINHTTP_DISABLE_KEEP_ALIVE;
int result = WinHttpSetOption(
g_hRequest,
WINHTTP_OPTION_DISABLE_FEATURE,
&dwOption,
sizeof(DWORD));
if (! result)
{
printf("WinHttpSetOption(3) err : %d\n", GetLastError());
return;
}
//*/

if (WINHTTP_INVALID_STATUS_CALLBACK ==
WinHttpSetStatusCallback(g_hRequest, zcCallBack, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0))
{
printf("WinHttpSetStatusCallback(2) err : %d\n", ::GetLastError());
return;
}

// *** *** *** Send ***

result = WinHttpSendRequest(
g_hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0,
0,
33);
if (! result)
{
printf("WinHttpSendRequest err : %d\n", GetLastError());
return;
}
}

DWORD g_dwCnt = 0;

void main()
{
printf("before zcTest\n");
system("PAUSE");

while (1)
{
g_dwCnt ++;
for (int i=1; i<50000; i++)
{
zcTest();

printf("zcTest out %d (%u)\n", i, g_dwCnt);
Sleep(500);
}
}
}


void ClearHandles()
{
BOOL bRtn = false;

if (g_hRequest)
{
if (WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback(g_hRequest, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0))
{ printf("WinHttpSetStatusCallback(3) err : %d\n", ::GetLastError()); }
bRtn = WinHttpCloseHandle(g_hRequest);
if (! bRtn)
{ printf("WinHttpCloseHandle g_hRequest - err : %d\n", ::GetLastError()); }
g_hRequest = NULL;
}
if (g_hConnect)
{
if (WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback(g_hConnect, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0))
{ printf("WinHttpSetStatusCallback(4) err : %d\n", ::GetLastError()); }
bRtn = WinHttpCloseHandle(g_hConnect);
if (! bRtn)
{ printf("WinHttpCloseHandle g_hConnect - err : %d\n", ::GetLastError()); }
g_hConnect = NULL;
}
if (g_hSession)
{
if (WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback(g_hSession, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0))
{ printf("WinHttpSetStatusCallback(5) err : %d\n", ::GetLastError()); }
bRtn = WinHttpCloseHandle(g_hSession);
if (! bRtn)
{ printf("WinHttpCloseHandle g_hSession - err : %d\n", ::GetLastError()); }
g_hSession = NULL;
}
}

void zcCrackUrl(WCHAR* _url)
{
g_uc.dwStructSize = sizeof(g_uc);

g_uc.lpszHostName = g_ucHost;
g_uc.dwHostNameLength = BUF_LEN;

g_uc.lpszUrlPath = g_ucPath;
g_uc.dwUrlPathLength = BUF_LEN;

WCHAR extra[BUF_LEN];
g_uc.lpszExtraInfo = extra;
g_uc.dwExtraInfoLength = BUF_LEN;

if (!WinHttpCrackUrl(_url, 0, ICU_ESCAPE, &g_uc))
{
printf("WinHttpCrackUrl err : %d\n\n", ::GetLastError());
}
}

void CALLBACK zcCallBack(
IN HINTERNET _hInternet,
IN DWORD_PTR _dwContext,
IN DWORD _dwInternetStatus,
IN LPVOID _lpvStatusInformation OPTIONAL,
IN DWORD _dwStatusInformationLength)
{
if (_dwContext == 33)
{
if (_dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE)
{
int result = WinHttpReceiveResponse(g_hRequest, 0);
if (! result)
{
return;
}
}
else if (_dwInternetStatus == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE)
{
char bufHeaders[1024] = {0};
DWORD dwSizeHeaders = 1024;
int result = WinHttpQueryHeaders(
g_hRequest,
WINHTTP_QUERY_STATUS_CODE,
WINHTTP_HEADER_NAME_BY_INDEX,
bufHeaders,
&dwSizeHeaders,
WINHTTP_NO_HEADER_INDEX);
if (result)
{
printf("WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE(%d) : %S\n", dwSizeHeaders, bufHeaders);
}
}
else if (_dwInternetStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE)
{
printf("WINHTTP_CALLBACK_STATUS_READ_COMPLETE(%d) : \n", _dwStatusInformationLength);
}
}
}


运行效果:
20130711.8:31开始运行。
20130711.9:14 运行效果见下图:


20130711.11:09 运行效果见下图:


20130711.12:49 运行效果见下图:



求各位帮帮忙啊,指出问题所在啊~~ 万分感谢。


...全文
459 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
CCDDzclxy 2013-11-06
  • 打赏
  • 举报
回复
引用 22 楼 zgl7903 的回复:
是不是和安装的防火墙 杀毒软件有关?
XP Home Edition 版本2002 sp2 裸奔
CCDDzclxy 2013-11-06
  • 打赏
  • 举报
回复
引用 22 楼 zgl7903 的回复:
是不是和安装的防火墙 杀毒软件有关?
XP裸奔机
zgl7903 2013-11-06
  • 打赏
  • 举报
回复
是不是和安装的防火墙 杀毒软件有关?
imkuang 2013-11-06
  • 打赏
  • 举报
回复
我也出了类似问题,用的是同步方式获取结果。程序占用内存缓慢增大。代码其实就是msdn上的示例代码。
xingzhou 2013-07-16
  • 打赏
  • 举报
回复
不用WinHttp好多年,先关注。
CCDDzclxy 2013-07-15
  • 打赏
  • 举报
回复
引用 18 楼 dream238 的回复:
Sleep(500); 会不会是你的测试代码有问题,有些操作耗时较长,未等结束就进行下一次操作了。
我这里的测试网址 “https://passport.jd.com/new/login.aspx”是可以连通的,还一个不能连通的网址的话,貌似 WinHttpReceiveResponse 必出 12017.
引用 18 楼 dream238 的回复:
而且都是全局的WINHTTP HANDLE,异步强制关闭,难说会泄露...
比如我网址连不通,我总得关闭句柄吧,我不能一直在那边等吧,我关闭句柄就会有 12017 啊,然后 线程退出码也就 != 0 喽...
ArcRain 2013-07-15
  • 打赏
  • 举报
回复
Sleep(500); 会不会是你的测试代码有问题,有些操作耗时较长,未等结束就进行下一次操作了。 而且都是全局的WINHTTP HANDLE,异步强制关闭,难说会泄露...
CCDDzclxy 2013-07-15
  • 打赏
  • 举报
回复
引用 16 楼 shen_wei 的回复:
我也不明白为啥有的不能正常退出,没有找到解决方法。。不是固定位置,无规律。。
12017 貌似是 WinHttpReceiveResponse 的 句柄 被 WinHttpCloseHandle 时报的错(ERROR_WINHTTP_OPERATION_CANCELLED)。 但是,不知为啥 WinHttpReceiveResponse 出错 会导致 线程也不正常退出?不是应该允许 WinHttpReceiveResponse 出错的么?
shen_wei 2013-07-15
  • 打赏
  • 举报
回复
F5,调试模式。。看输入信息就可以了!! 我也不明白为啥有的不能正常退出,没有找到解决方法。。不是固定位置,无规律。。
CCDDzclxy 2013-07-15
  • 打赏
  • 举报
回复
引用 14 楼 shen_wei 的回复:
线程 'Win32 线程' (0xe38) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0xfd4) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x274) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x900) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x940) 已退出,返回值为 12017 (0x2ef1)。
线程 'Win32 线程' (0x514) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0xd28) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0xbfc) 已退出,返回值为 12017 (0x2ef1)。
线程 'Win32 线程' (0xf64) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x6d0) 已退出,返回值为 997 (0x3e5)。
线程 'Win32 线程' (0xd00) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x82c) 已退出,返回值为 0 (0x0)。
在运行时,有些线程不能正常退出。。不知道啥原因。。 返回值为0,代表正常退出。
请问,你上面的打印出来的信息是怎么弄出来的??
shen_wei 2013-07-15
  • 打赏
  • 举报
回复
线程 'Win32 线程' (0xe38) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0xfd4) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x274) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x900) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x940) 已退出,返回值为 12017 (0x2ef1)。
线程 'Win32 线程' (0x514) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0xd28) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0xbfc) 已退出,返回值为 12017 (0x2ef1)。
线程 'Win32 线程' (0xf64) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x6d0) 已退出,返回值为 997 (0x3e5)。
线程 'Win32 线程' (0xd00) 已退出,返回值为 0 (0x0)。
线程 'Win32 线程' (0x82c) 已退出,返回值为 0 (0x0)。
在运行时,有些线程不能正常退出。。不知道啥原因。。 返回值为0,代表正常退出。
CCDDzclxy 2013-07-14
  • 打赏
  • 举报
回复
引用 11 楼 songsu 的回复:
我和你一样也遇到这个问题,同关注。
引用 12 楼 songsu 的回复:
vs2008+xp
我在 Win7 和 Win2003 上用 VC6、vs08、vs2010 编译的顶楼代码,产生的exe,跑12小时,都有此现象,不知是哪边不对。 期待高手能指出来,谢谢。
songsu 2013-07-14
  • 打赏
  • 举报
回复
vs2008+xp
songsu 2013-07-14
  • 打赏
  • 举报
回复
我和你一样也遇到这个问题,同关注。
CCDDzclxy 2013-07-13
  • 打赏
  • 举报
回复
引用 8 楼 davidyu720 的回复:
今天跑了一小时,从taskmgr看,没有什么泄漏,挺正常的。 看了代码,也不会有内存泄漏和句柄泄漏。
为哈 我这就有漏? 你是 什么编译器?什么os?
davidyu720 2013-07-13
  • 打赏
  • 举报
回复
VC6 WINXP-SP3
davidyu720 2013-07-12
  • 打赏
  • 举报
回复
今天跑了一小时,从taskmgr看,没有什么泄漏,挺正常的。 看了代码,也不会有内存泄漏和句柄泄漏。
CCDDzclxy 2013-07-12
  • 打赏
  • 举报
回复
引用 6 楼 zhao4zhong1 的回复:
检查是否资源泄漏的办法之一: 在任务管理器 进程 查看 选择列 里面选择:内存使用、虚拟内存大小、句柄数、线程数、USER对象、GDI对象 让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有对应资源的资源泄漏!
请对比 顶楼 和 5楼 的图片,我就是在 无限循环着的啊... 现在是第二天时间 ,现象已经可以看得出来了吧...
赵4老师 2013-07-12
  • 打赏
  • 举报
回复
检查是否资源泄漏的办法之一: 在任务管理器 进程 查看 选择列 里面选择:内存使用、虚拟内存大小、句柄数、线程数、USER对象、GDI对象 让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有对应资源的资源泄漏!
CCDDzclxy 2013-07-12
  • 打赏
  • 举报
回复
引用 2 楼 davidyu720 的回复:
内存使用仅仅从4M增长到5M,句柄数一直是171~173,看起来比较正常。

楼顶的图片可能是运行时间不久吧,看今天得两张图:(20130711.8:31开始运行,到现在,该测试exe未关闭重启 !)
20130712_0926.JPG (20130712早上09:26):

20130712_1625.JPG (20130712下午16:25):



代码就那么长,复制粘贴即可编译运行,帮帮忙,有闲空的话,帮小弟看看测试下,谢谢。

加载更多回复(4)

16,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧