注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

mie

 
 
 

日志

 
 

【★★★★★】GDI+ 绘图导致内存页面错误频繁  

2011-04-10 15:22:15|  分类: 疑难杂症 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
GDI+ 绘图导致内存页面错误频繁

       几个概念:虚拟内存、物理内存、页面交换
       (1)物理内存。电脑主板上面的几根内存条,就是所谓的物理内存,也就是实际存在的内存。
       (2)虚拟内存。操作系统虚拟出来的内存。早期的计算机,物理内存有限,而且硬盘速度很慢,从物理内存访问硬盘需要很多的系统时间,这是计算机的“瓶颈”之一,设计者们虚拟内存创造了这个技术,一方面可以解决物理内存不足导致的问题,同时,也解决了从物理内存到硬盘之间数据传输的瓶颈。例如:Windows系统下默认的C盘的pagefile.sys文件,linux的swap交换分区,就是虚拟内存。查看方法:打开“我的电脑”,点击菜单“工具”——“文件夹选项”——“查看”,将“隐藏受保护的操作系统文件(推荐)”前面的勾去掉,“确定”。打开C盘,就可以看到虚拟内存文件了。虚拟内存的修改:在“我的电脑”图标上面右击,选择“属性”,“高级”,点击“性能”(视觉效果...)旁边的设置按钮,选择“高级”选项卡,点击“更改”按钮,弹出虚拟内存的设置窗口修改,即可。
         即:物理内存就是硬件,而虚拟内存就是磁盘文件或者磁盘分区。
        (3)进程的内存空间。进程的内存空间也是虚拟的,但是和虚拟内存又是两码事。一个进程的内存包括虚拟内存和物理内存。对于32位的系统,windows给每个进程设定了4GB的内存空间,即使你的物理内存只有2GB,也是一样。为了防止恶意破坏,windows将内存再分成用户模式和内核模式。用户模式运行一般的代码,也就是通常所说的ring3;内核模式运行系统关键代码,也就是所谓的ring0。exe文件不一定就是ring3的,虽然大部分情况下是这样;驱动程序也不一定就是ring0的。
          默认情况下,系统将进程的内存分为2GB的用户模式和2GB的内核模式。
          这4GB的内存是虚拟的,其中有一部分是物理内存,另外一部分是虚拟内存。我们的代码基本上都是物理内存运行。但是,可能软件本身占用的内存很大,如果都使用物理内存,电脑吃不消。而且,如果运行一个几百MB的软件,启动时,将几百MB的数据完全从硬盘读到物理内存中,也需要很多的时间。同时,这几百MB的数据,并不是软件时刻都需要使用到的,这就造成了内存的浪费。所以,系统将不需要的数据从物理内存备份到虚拟内存,腾出物理内存空间,供其他软件使用,也就是所谓的“页面交换”。
        页面交换。系统会访问进程的内存页表,去寻找物理内存的地址,并试图访问之。当物理内存被交换到虚拟内存时,物理内存页面也就不存在了,此时再访问这个内存页面,操作系统会触发一个系统中断,也就是“缺页中断”。关于中断,可以查看《操作系统原理》方面的资料。之后,操作系统的中断例程(也就是一个函数)会处理相应的事件,对于缺页中断,操作系统就从虚拟内存取得相应的页面的数据,交换到物理内存中。至此,再访问物理内存,就可以取得相应的数据了。
         产生缺页中断,在windows上层的表现就是缺页错误,也就是我的程序遇到的这种情况。关于缺页错误的查看,可以打开“任务管理器”,点击菜单“查看”——“选择列”,勾上“页面错误”,“确定”。之后就可以看到页面错误的统计数据。也可以勾上“页面错误增量”,实时查看当前单位时间内产生的页面错误数目。

2011.04.05:
        内存页面错误
        去年遇到过这个问题,当时由于代码较多,不方便定位,也就忽略了。当时的情况相当可怕,软件运行一个小时,页面错误的数目竟然达到十几亿。这次用到类似的技术,所以,加入了一部分可能导致类似问题的代码后,立刻跟踪,从而重现问题!

        难道GDI+会导致频繁交换页面内存?还是我的代码写法不对?为此,我做了简单的统计。

(1)ImageAttributes::SetColorMatrix
调用此函数会触发两次页面错误。
(2)Graphics::DrawImage
触发两次页面错误。
(3)API函数,GetBitmapBits
触发两百多次页面错误。

2011.04.10:
        还有其他地方,就不再列出来了。现在的代码量也不少了,跟踪也不如前段时间方便。不过,对于页面交换的问题,还是得解决!到目前为止,没有看到过别的软件的内存交换有我的这几个软件频繁。我想,必然是某些地方的写法有问题。比如,GetBitmapBits,这类函数不应该频繁调用,应该一次调用,并保存为变量。——不管怎么说,这个问题非常之严重!目前认为,很可能是绘制频繁导致的。频繁绘制,绘制过程中,又频繁调用GetBitmapBits这类会触发系统进行大量页面交换的函数,于是就有了这个奇怪的现象。

2011.04.11:
      昨晚,想起另外一个问题。事实上,自己调用GetBitmapBits,是错误的!我只是获取位图的BITMAP结构,应该调用GetObject函数!而我却写成GetBitmapBits!GetBitmapBits是获取位图的原始数据,或者说是“raw data”(个人很喜欢raw data这个词语),对于32位的400×300的位图,原始数据就有32*400*300/8=约480KB,换算成分页内存,约120页。假设位图的raw data被调度到虚拟内存,此时,调用GetBitmapBits就至少触发120次换页中断,也就是120次的页面错误。——而去年遇到的问题,原因很可能就是因为这个!

BY:章永辉
  评论这张
 
阅读(682)| 评论(1)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016