ImageVerifierCode 换一换
格式:DOCX , 页数:24 ,大小:672.97KB ,
资源ID:26411925      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/26411925.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(内存泄漏检查.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

内存泄漏检查.docx

1、内存泄漏检查内存泄漏检测方法 对于不同的程序可以使用不同的方法来进行内存泄漏的检查,还可以使用一些专门的工具来进行内存问题的检查,例如MemProof、AQTime、Purify、BundsChecker等。 也可以使用简单的办法:利用Windows自带的Perfmon来监控程序进程的handle count、Virtual Bytes和Working Set 3个计数器。 Handle Count记录了进程当前打开的句柄个数,监视这个计数器有助于发现程序是否存在句柄类型的内存泄漏;Virtual Bytes记录了程序进程在虚拟地址空间上使用的虚拟内存的大小,Virtual Bytes一般总大

2、于程序的Working Set,监视Virtual Bytes可以帮助发现一些系统底层的问题;Working Set记录了操作系统为程序进程分配的内存总量,如果这个值不断地持续增加,而Virtual Bytes却跳跃式地增加,则很可能存在内存泄漏问题。 堆栈内存泄漏 堆栈空间不足会导致在受托管的情况下引发StackOverflowException类型的异常,线程泄漏是堆栈内存泄漏的其中一种。线程发生泄漏,从而使线程的整个堆栈发生泄漏。 如果应用程序为了执行后台工作而创建了大量的工作线程,但却没有正常终止这些线程,则可能会引起线程泄漏。 一个堆栈内存泄漏的例子:private void but

3、ton1_Click(object sender, EventArgs e) / 循环启动多个线程 for (int i = 0; i 1500; i+) Thread t = new Thread(new ThreadStart(ThreadProc); t.Start(); static void ThreadProc() Console.WriteLine(启动 Thread #0 ,Thread.CurrentThread.ManagedThreadId); / 阻塞直到当前线程结束 Thread.CurrentThread.Join(); 利用Perfmon检测线程堆栈泄漏 默认堆栈

4、大小为1MB,因此如果应用程序的Private Bytes不断增大,同时.NET CLR LocksAndThreads中的 # of current logical Threads 也相应地增大,那么就很可能是发生了线程堆栈泄漏。 可以利用Perfmon来判断是否存在内存泄漏现象。 执行被测试程序的相关操作,并在性能监视器中密切注意“Private Bytes”和“# of current logical Threads”两个计数器的变化曲线,如果Private Bytes不断增大,同时# of current logical Threads 也相应地增大,则可判断程序发生了线程堆栈泄漏。

5、用CLRProfiler定位线程泄漏代码利用CLRProfiler可以帮助检查程序是否存在线程泄漏。方法如下:(1)启动CLRProfiler (2)单击“Start Application”按钮 (3)选择需要测试的应用程序,单击“打开”按钮。CLRProfiler会自动打开被测试程序,执行程序的相关操作,然后单击CLRProfiler的“Show Heap Now”按钮 说明:这个界面显示了程序的所有堆分配的情况。其中可以看到线程类中分配了82K,占了18%以上,其中包含1500个线程对象。(4)选中“Threading.Thread”的节点,单击右键,选择“Show Who Alloca

6、ted” 说明:在这个界面中可以看到是哪个类的哪个方法创建了这么多的线程对象,在这里可以看到是由button1_Click方法调用了线程类,从而定位到引发线程泄漏的代码。 资源泄漏 资源通常指系统的对象。例如GDI对象句柄、内存句柄等,在软件编程过程中,使用到很多这些资源对象,但是没有及时地释放掉就造成了资源泄漏。 GDI泄漏是指程序申请了GDI句柄,但是没有及时释放,导致GDI句柄不断累积。GDI泄漏可能导致系统不稳定,或者出现花屏。一个GDI泄漏的例子 : Form1: / 调用Form2窗体 Form2 f = new Form2(); / 显示Form2窗体 f.ShowDialog(

7、); Form2: private void Form2_Load(object sender, EventArgs e) / 使用pictureBox控件加载并显示一个图片 pictureBox1.Image = Image.FromFile(picture.JPG); private void Form2_FormClosing(object sender, FormClosingEventArgs e) / 如果少了这句,则会发生GDI资源泄漏 /pictureBox1.Image.Dispose(); 用Windows任务管理器协助检测GDI泄漏 对于上面的GDI泄漏代码,可以利用Wi

8、ndows的任务管理器来协助检测。方法如下:(1)首先打开Windows任务管理器 (2)选择菜单“查看 | 选择列”,出现如图15.13所示界面。确保“GDI对象”被勾选上,然后单击“确定”按钮。(3)启动被测试程序ResourceLeak(即上面的代码例子的可执行程序),并在Windows任务管理器中定位到被测试程序的进程 (4)记下应用程序进程的当前GDI对象数,然后运行程序的各项操作,在操作过程中密切关注其GDI对象数的变化,例如,对于ResourceLeak.exe进程,当前的GDI对象数是33,如果点击button1,程序将调出第二个窗口,窗口加载了一个图片,这个过程会向系统申请一

9、些GDI对象资源,因此查看Windows任务管理器可以看到其GDI对象数的变化 (5)这时候,把第二个窗口关闭,如果程序存在资源泄漏,则GDI对象数不会减少到33。而且反复操作程序,调出第二个窗口再关闭,可看到GDI对象数不断地增加,这样就可判断程序存在GDI资源泄漏的现象。 利用GdiUsage 检查GDI泄漏 GdiUsage是Christophe Nasarre写的一个专门用于检查程序使用GDI资源情况的小工具 它的使用方法也很简单,具体使用方法如下:(1)首先在上面的输入框输入需要测试的程序路径,然后按“Start”按钮启动被测试程序,程序被启动的同时,GdiUsage会显示一个“De

10、buggee Output”窗口,用于展示程序加载的DLL名称以及地址 (2)启动程序后,在GdiUsage中单击“Take Snapshots”按钮,给当前程序使用的GDI资源情况取一个“快照” (3)可看到当前程序使用到1个Bitmap类型的GDI对象,单击“Details”按钮,还可以看到详细的资源展示界面 (4)接着操作被测试程序(单击ResouceLeark程序的button1按钮),再单击一下“Take Snapshots”按钮,给当前程序使用的GDI资源情况取一个“快照” (5)可以看到当前程序使用的Bitmap对象增加到2个,Region对象增加1个。这时关闭ResouceLe

11、ark程序的Form2窗口,再取一个快照,则发现Bitmap对象和Region对象的个数都未减少,并且如果重复这个过程,Bitmap对象的个数会不断地增加。因此可以认为程序存在资源泄漏的现象。GDI与GDI+1、概述 GDI在全称是Graphics Device Interface,即图形设备接口。是图形显示与实际物理设备之间的桥梁。GDI接口是基于函数,虽然使程序员省力不少,但是编程方式依然显得麻烦。例如显示一张位图,我们需要进行“创建位图,读取位图文件信息,启用场景设备,调色板变化“等一系列操作。然而有了GDI+,繁琐的步骤再次被简化。顾名思义,GDI+就是GDI的增强版,它是微软在Win

12、dows 2000以后操作系统中提供的新接口。2、GDI+主要功能 GDI+主要提供以下三种功能: (1) 二维矢量图形:GDI+提供了存储图形基元自身信息的类(或结构体)、存储图形基元绘制方式信息的类以及实际进行绘制的类; (2) 图像处理:大多数图片都难以划定为直线和曲线的集合,无法使用二维矢量图形方式进行处理。因此,GDI+为我们提供了Bitmap、Image等类,它们可用于显示、操作和保存BMP、JPG、GIF等图像格式。 (3) 文字显示:GDI+支持使用各种字体、字号和样式来显示文本。 相比于GDI,GDI+是基于C+类的对象化的应用程序接口,因此用起来更为简单。GDI的核心是设备

13、上下文,GDI函数都依赖于设备上下文句柄,其编程方式是基于句柄的;GDI+无需时刻依赖于句柄或设备上下文,用户只需创建一个Graphics 对象,就可以用面向对象的方式调用其成员函数进行图形操作,编程方式是基于对象的。3、GDI绘制实例 GDI在使用设备上下文绘制线条之前,必须先调用SelectObject 以使笔对象和设备上下文关联。其后,在设备上下文中绘制的所有线条均使用该笔,直到选择另一支不同的笔为止。 使用GDI画线代码如下/ TODO: Add your command handler code here CClientDC clientDC; /目标DC CPen pen (PS_

14、SOLID, 1, RGB(0, 0, 255); clientDC.SelectObject(pen.GetSafeHandle(); /开始绘制 clientDC.MoveTo(0, 0) clientDC.LineTo(rect.right, 0); clientDC.SelectObject(oldObject); 从上述代码可以看出:在GDI编程中,几乎所有的操作都围绕设备上下文dc展开。的确,这正是GDI编程的特点!设备上下文是 Windows 使用的一种结构,所有GDI操作前都需取得特定设备的上下文,函数中的CClientDC dc (this) 语句完成这一功能。 利用GDI进

15、行图形、图像处理的一般操作步骤为:1. 取得指定窗口的DC。2. 确定使用的坐标系及映射方式。3. 进行图形、图像或文字处理。4. 释放所使用的DC。但是,在GDI+中,只需将Pen对象直接作为参数传递给Graphics类的DrawLine等方法即可,而不必使Pen对象与 Graphics对象关联。4、GDI+绘制实例 使用GDI+画线代码如下 / TODO: Add your command handler code here CClientDC clientDC (this); /创建Graphics对象Graphics graphics(clientDC);/创建penPen myPen

16、;myPen.SetWidth(1);/画X轴myPen.SetColor(Color:Blue);graphics.DrawLine(&myPen, 0, 0, rect.right, 0); (1)创建 Graphics 对象:Graphics 对象表示GDI+绘图表面,是用于创建图形图像的对象。 (2)使用 Graphics 对象绘制线条和形状、呈现文本或显示与操作图像。 GDI+的相对与GDI而言,新增了一系列功能:渐变的画刷(Gradient Brushes)、基数样条函数(Cardinal Splines)、持久的路径对象(Persistent Path Objects)、变形和矩

17、阵对象(Transformations &Matrix Object)、可伸缩区域(Scalable Regions)、Alpha混合(Alpha Blending)和丰富的图像格式支持等。下面,我们来逐个用实际代码实现GDI+的新增功能。非托管资源造成的内存泄漏在.NET开发中容易被忽视,引起内存泄漏通常存在于以下三种情况:1. 对象被引用而没有被释放2. 没有释放非托管资源3. 没有释放非托管资源封装对象上个章节描述的EventHanlder和Delegate造成的内存泄漏就属于第一类,之所以要单独拿出来叙述是因为.NET事件和代理造成的内存泄漏相对于静态变量的根化引用更容易被忽略且不好被

18、识别出来。第2类和第3类同属于系统资源类型造成的内存泄漏,但是又有所区别。第二类是指通过本地API函数与托管对象进行交互(比如:通过 P/Invoke方式调用本地DLL,DLLImport声明静态外部函数和COM Interop)所用到的非托管资源。例如:当通过DLL Import调用 API函数GetDC函数时忘了调用ReleaseDC去释放设备句柄造成4个字节的内存泄漏。再如:智能文档中使用的Word以及导出EXCEl功能用到的Office的COM非托管组件,在关闭时GC不能识别COM组件而造成有时候无法对COM对象进行释放,这时候可以通过以下两个InteropServices函数进行释放

19、 System.Runtime.InteropServices.Marshal.ReleaseComObject(comObject); System.Runtime.InteropServices.Marshal.FinalReleaseComObject(comObject);上次在敏捷交流了内存相关事项问题后,给大家留了几道思考题,其中第一道题是“数据库连接SqlConnection是不是非托管资源,为什么?”,有些人的回答是“肯定”,之所以有这样回答是因为大家所了解的非托管资源的经典认知就是数据库连接、文件、网络连接都是非托管资源,有人认为SqlConnection就是数据库连接,其实

20、不然,.NET对某些非托管资源提供一种包装类,SqlConnection就是这种,包装类的源(WrapSource)才真正是托管资源,它管理了非托管资源,而它本身确实托管的。 .NET GDI Plus中常用的Drawing命名空间下的类很多就是这种包装类型,现将常用的几种非托管包装类列举如下:ApplicationContextComponentComponentDesignerBrushContainerContextCursorFileStreamDataSetFontIconImageMatrixTextureOdbcDataReaderOleDBDataReaderPenRegexS

21、ocketStreamWriterTimerTooltipBitmap识别这种包装类型的主要方法就是通过MSDN查询是否该对象继承于System.MarshalByRefObject类。做一个实验来测试Graphics的释放,新建一个Form对象,在Form对象的Paint事件里,写入以下代码,用于在Form2上绘制。Bitmapbmp = newBitmap(600, 600);Graphicsg = Graphics.FromImage(bmp);Brushbrush = newLinearGradientBrush (newPointF(0.0f, 0.0f),newPointF(700

22、.0f, 300.0f),Color.Blue, Color.Red);for (intj = 0; j 60; +j)for (inti = 0; i 60; +i)g.FillEllipse(brush, i * 10, j * 10, 10, 10);this.CreateGraphics().DrawImage(bmp, 0, 0); 运行起来发现,不停的移动Form2,对应刷新Form2的Paint事件,在内存管理器里面可以看到实验程序的内存会不停的增长,这说明这时候已经产生了内存泄漏了。 启动AQTime,并启用Resource Profiler调试方案,运行程序,隔一段时间调用“

23、Get Result”收集数据。 第一次收集数据,GpGrahics对象的LiveCount =3;第二次收集数据,GpGrahics对象的LiveCount =21;GpGraphics对象的持续增长说明,GpGraphics造成了内存泄漏,再利用.NET Memory Profiler捕捉内存Heap快照。显示方法中的Bitmap、Graphics、LinearGradientBrush三种类型出现了“Undisposed Instances”警告。这里,因为Graphics没有释放导致Grahics上引用的Bitmap,以及Bimap上的LinearGradientBrush对象都没有被

24、及时释放,造成内存泄漏。将代码修改如下:using (Graphicsg1 = this.CreateGraphics() using (Bitmapbmp = newBitmap(600, 600) using (Graphicsg = Graphics.FromImage(bmp) using (Brushbrush = newLinearGradientBrush (newPointF(0.0f, 0.0f),newPointF(700.0f, 300.0f),Color.Blue, Color.Red) for (intj = 0; j 60; +j)for (inti = 0; iN

25、ew Project.2).在Setup添加LuboView.exe。3).选择Profiler为Resource Profiler。4).点击Run按钮,在弹出的对话框中点击Run。5).在Event View中可以查看到以下信息:EventThread IDTime-Project run selected, current profiler is Resource Profiler.15:18:30:843Product: AQtime; Version: 4.92.669.0-Work environment:Host name: SOHU-ZGDMOS: Microsoft Wind

26、ows XP Service Pack 2 5.1 Build 2600Windows directory: C:WINDOWS; System directory: C:WINDOWSSYSTEM32Current user: AdministratorNumber of processors: 2Processor: Intel(R) Pentium(R) D CPU 3.00GHz, Frequency: 2992 MHz.Memory in use: 42%Total Physical Memory: 2,145,427,456 bytes; Available Physical Memory: 1,238,437,888 bytes; Total Virtual Memory: 2,147,352,576 bytes; Available Virtual Memory: 1,806,143,488 bytes; Virtual Memory In Use: 341,209,088 bytesMicrosoft .NET Framework version: v2.0.50727-Run Mode:

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1