VirtualAlloc失败

 引用 http://topic.csdn.net/u/20080128/09/c2678506-4193-4bfe-aaef-1c2b30520245.html
我在程序中用了VirtualAlloc进行内存申请,因为后面的一个函数需要按页大小分配的空间。

现在问题是,我的程序运行一段时间后(大约2个小时),会频繁的出现VirtualAlloc失败的情况,我不清楚是怎么出现的。

出现问题时,机器的内存很充裕, 我怀疑是因为内存碎片过多导致的,但现在还不知道怎么用工具查看,没办法确认。

程序的大概逻辑:
监听服务端口,接收客户端请求,按客户端的请求数据大小申请内存(VirtualAlloc),从本地文件读取数据,然后将数据发给客户端。
问题点数:100 回复次数:21 显示所有回复显示星级回复显示楼主回复 修改 删除 举报 引用 回复
VirtualAlloc失败_第1张图片
加为好友
发送私信
在线聊天
  • zzz3265
  • Yofoo
  • 等级:
  • 可用分等级:中农
  • 总技术分:17011
  • 总技术分排名:818
发表于:2008-01-28 09:46:481楼 得分:5
出错的时候写日志, 参数, 返回值, LastError 都记录下来

VirtualAlloc, 当size为 0, 或者太大 都可能会出错
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 09:52:272楼 得分:0
补充一下,调用方式如下:
void *addr =  ::VirtualAlloc (NULL,
                                    chunk_size,
                                    MEM_COMMIT,
                                    PAGE_READWRITE);
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 09:57:053楼 得分:0
to zzz3265 :

谢谢你的建议,我开始的确没有记录错误码和参数信息,后来发现这个问题后补充上去了。现在等这个问题重现。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • zhoujianhei
  • 高手.高手.高高手
  • 等级:
  • 可用分等级:中农
  • 总技术分:16752
  • 总技术分排名:990
发表于:2008-01-28 10:04:054楼 得分:0
按照你的逻辑,可以不使用VirtualAlloc  的,直接内存映射文件不是很好吗?
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 14:26:145楼 得分:0
错误码:
ERROR_NOT_ENOUGH_MEMORY

很奇怪,任务管理器上的内存是很多的,我每次只请求4K而已,也会报这个错?

to zhoujianhei:
我在后面用到了的分散读的接口ReadFileScatter,需要这样分配内存空间。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • unsigned
  • 僵哥(重要的不是为之付出了多少,误导才是最大的失败)
  • 等级:
  • 可用分等级:长工
  • 总技术分:77211
  • 总技术分排名:80
  • 3

    2

    5

发表于:2008-01-28 14:33:406楼 得分:0
错误码:
ERROR_NOT_ENOUGH_MEMORY

很奇怪,任务管理器上的内存是很多的,我每次只请求4K而已,也会报这个错?
=================================
能否提供详细的配置信息,以当前任务管理器上面显示的详细信息。特别是OS版本,内存及硬件配置,以及相关的启动参数;基本内存使用状况,未分页内存(核心内存,此项有一定的相关性,但并不是太大)等等。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 14:52:517楼 得分:0
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 14:54:348楼 得分:0
基本信息如上图,现在已经频繁的出现virtualalloc失败的情况
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 14:57:599楼 得分:0
OS版本:
windows server 2003
Enterprise Edition
Service Pack 2
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 15:07:2210楼 得分:0
用PE查看的该进程的性能图片:
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • zhoujianhei
  • 高手.高手.高高手
  • 等级:
  • 可用分等级:中农
  • 总技术分:16752
  • 总技术分排名:990
发表于:2008-01-28 15:12:0411楼 得分:10
C/C++ code
            
            
            
            
void * addr = ::VirtualAlloc (NULL, chunk_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

试试。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 15:38:5112楼 得分:0
to zhoujianhei :

谢谢你的建议,我正在尝试你的方法,不过效果要等一段时间。

MEM_COMMIT|MEM_RESERVE 这两个参数,按msdn上所说,应该包含一个就可以了,同时指定这两个参数,有什么好处呢?
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • unsigned
  • 僵哥(重要的不是为之付出了多少,误导才是最大的失败)
  • 等级:
  • 可用分等级:长工
  • 总技术分:77211
  • 总技术分排名:80
  • 3

    2

    5

发表于:2008-01-28 16:08:5213楼 得分:70
刚测试过,问题关键并不在于使用的参数,而是VirtualAlloc之后,每个申请都要占用相应的核心内存,从而导致申请一定次数之后,核心内存(估计分配就单个应用程序有一定的限制)就达到限额,而报内存不足。

下面是两段测试代码(注:这是测试代码,正常业务代码不得仿写)

1.每次申请一个字节
C/C++ code
            
            
            
            
for ( int i = 0 ; i < 10240 ; i ++ ) { void * addr = ::VirtualAlloc( NULL, 1 , MEM_COMMIT, PAGE_READWRITE); if ( ! addr) break ; }



2.每次申请申请一个字节40960字节(大概为十页,我这里是2GB物理内存,如果物理内存较小,这个数字可以改小一点)
C/C++ code
            
            
            
            
for ( int i = 0 ; i < 10240 ; i ++ ) { void * addr = ::VirtualAlloc( NULL, 40960 , MEM_COMMIT, PAGE_READWRITE); if ( ! addr) break ; }


在我这里执行的结果是,前者分配的内存很少,依然会报出错误:ERROR_NOT_ENOUGH_MEMORY.而后者分配到了1.9G.
但是有一个相同的就是对于核心内存(未分页内存,打开任务管理器->转到[进程]页->选择[查看]菜单的[选择列...]菜单项->勾选[未分页缓冲池],即可看到),到报错的时候,都是1257k.
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • zhoujianhei
  • 高手.高手.高高手
  • 等级:
  • 可用分等级:中农
  • 总技术分:16752
  • 总技术分排名:990
发表于:2008-01-28 16:20:0114楼 得分:0
for (int i = 0; i < 10240; i++) {
  void *addr = ::VirtualAlloc( NULL,
                              40960,
                              MEM_COMMIT,
                              PAGE_READWRITE);
  if (!addr)
    break;
}
==============================================
如果这样用法,建议使用内存池。
你造成的碎片太多啦。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • unsigned
  • 僵哥(重要的不是为之付出了多少,误导才是最大的失败)
  • 等级:
  • 可用分等级:长工
  • 总技术分:77211
  • 总技术分排名:80
  • 3

    2

    5

发表于:2008-01-28 16:29:5415楼 得分:0
to 14楼,昏倒,我已经很明确写明是测试代码...
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • zhoujianhei
  • 高手.高手.高高手
  • 等级:
  • 可用分等级:中农
  • 总技术分:16752
  • 总技术分排名:990
发表于:2008-01-28 16:36:4916楼 得分:0
呵呵,眼花啦。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-01-28 17:04:1317楼 得分:0
unsigned 测试的结果和我刚才观察的现象比较相似,我的机器报错时,页面缓冲池是120K,非页面缓冲池是在1380K。

zhoujianhei 提到的内存缓冲池,应该是我解决这个问题的方法了。

多谢二位的建议,我先修改验证 :)
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • unsigned
  • 僵哥(重要的不是为之付出了多少,误导才是最大的失败)
  • 等级:
  • 可用分等级:长工
  • 总技术分:77211
  • 总技术分排名:80
  • 3

    2

    5

发表于:2008-01-28 17:13:3818楼 得分:0
zhoujianhei  提到的内存缓冲池,应该是我解决这个问题的方法了。
=================
如果是内存不足的话,那么缓冲池也未必解决得了问题,而如果是够用的话,那只能说明你调了VirtualAlloc申请了,没有配置的VirtualFree进行释放。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • cnzdgs
  • 回贴亦是善举
  • 等级:
  • 可用分等级:贫农
  • 总技术分:114970
  • 总技术分排名:43
  • 5

    2

    13

发表于:2008-01-28 19:09:5519楼 得分:5
这个问题看起来像是18的说法。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • nochater
  • 无聊仔
  • 等级:
  • 可用分等级:富农
  • 总技术分:223
  • 总技术分排名:55804
发表于:2008-01-28 19:41:0020楼 得分:10
这个问题基本上是代码写的不够严谨造成的
请你把注意力放在内存的释放上,或许你会找到答案
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Dream_lover
  • 等级:
  • 可用分等级:富农
  • 总技术分:298
  • 总技术分排名:46449
发表于:2008-02-05 15:18:5521楼 得分:0
VirtualAlloc之后,每个申请都要占用相应的核心内存,从而导致申请一定次数之后,核心内存(估计分配就单个应用程序有一定的限制)就达到限额,而报内存不足。

是这个道理, 应该是每次调用VirtualAlloc成功后,会在内核内存中进行相应的记录,从而导致内核内存增长。

我的问题是释放的地方用错了,VirtualFree的参数用了MEM_DECOMMIT,而不是MEM_RELEASE,所以没有真正释放内存。

谢谢大家的答复,要过年了,祝新年快乐 :)

你可能感兴趣的:(windows,测试,service,null,聊天,任务)