微软官方MSDN原版Win10系统下载

现在位置: 首页  > 系统教程  > 系统帮助

如何避免内存泄露

时间:2024-09-20 12:18:47   

大家好,今天Win10系统之家小编给大家分享「如何避免内存泄露」的知识,如果能碰巧解决你现在面临的问题,记得收藏本站或分享给你的好友们哟~,现在开始吧!

生意如何小账本专业版-小商户销售和存货记账系列软件最新版本下载

1.什么是内存泄漏 如何避免


  内存泄漏可以分为4类: 
1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。 
2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。 
3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。 
4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。 
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。

2.工程中如何尽量避免C/C++内存泄露


  C/C++软件工程实现中,内存泄露可能是一个让众多程序员懊恼的问题. 内存泄露问题是如此普遍并且被认为是难以解决,标明内存泄露不是一个理论上的问题, 而是一个实践中的问题. 假若它是一个理论上的问题, 那么它肯定早就从理论上加以解决而不再是一个问题.软件工程实践中, 应该努力采用良好的设计策略和代码习惯来尽量避免内存泄露; 说避免并非是逃避困难而是规避内存泄漏遍及代码导致不可控的风险和测试阶段导致的疲于奔命. 下面总结几个关乎内存泄漏的设计原则:1. 尽量不设计内部分配内存而该内存传到外部使用的接口;2. 当内存是系统或模块内部分配并且需要传给外部时(不可更改性接口需求时), 为了在特定上下文/线程/环境终止时清理内部分配的与之相关的内存, 那么这时系统需要引入一个也许并不复杂的全局内存管理器;3. 与特定上下文/线程/环境系统所有内存分配/释放操作都经由这个内存管理器来追踪; 在软件规模增大时, 多种分配方式的使用只会带来混乱从而不可避免的导致内存泄露; 4. 对于与特定上下文/线程/环境相关的接口, 外部无法预先知道缓冲区大小需求的情况(如IO, 一般有内部缓冲区且有足够的状态和信息), 或者与特定上下文无关,但能根据传入参数知道需要缓冲大小的接口(如协议包序列化参数含大小), 接口需要支持:首先传递NULL缓冲区指针,返回需要的缓冲区大小; 传入的缓冲区大小太小时,返回缓冲小错误码;传入的缓冲区足够时,拷贝输出数据.5. 系统中与特定上下文无关的接口或者业已存在的, 外部无法预先知道缓冲区大小需求的情况, 使用特定上下文进行封装, 其分配的内存注册到内存管理器中, 使用完毕后需要调用内存管理器释放接口显式释放, 尽量将其使用控制在特定层次内.6. 使用内存泄露工具检查整个系统.

3.C语言中的内存泄露 怎样避免与检测


  常见的内存错误及其对策如下:
1、内存分配未成功,却使用了它
 编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数
的入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
2、内存分配虽然成功,但是尚未初始化就引用它
 犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。
 内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零
值也不可省略,不要嫌麻烦。
3、内存分配成功并且已经初始化,但操作越过了内存的边界
例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。
4、忘记了释放内存,造成内存泄露
含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。
未初始化的内存
在本例中,p 已被分配了 10 个字节。这 10 个字节可能包含垃圾数据。
char *p = malloc ( 10 );
如果在对这个 p 赋值前,某个代码段尝试访问它,则可能会获得垃圾值,您的程序可能具有不可预测的行为。p 可能具有您的程序从未曾预料到的值。
良好的实践是始终结合使用 memset 和 malloc,或者使用 calloc。
char *p = malloc (10);
memset(p,’\0’,10);
现在,即使同一个代码段尝试在对 p 赋值前访问它,该代码段也能正确处理 Null 值(在理想情况下应具有的值),然后将具有正确的行为。
内存覆盖
由于 p 已被分配了 10 个字节,如果某个代码片段尝试向 p 写入一个 11 字节的值,则该操作将在不告诉您的情况下自动从其他某个位置“吃掉”一个字节。让我们假设指针 q 表示该内存。
结果,指针 q 将具有从未预料到的内容。即使您的模块编码得足够好,也可能由于某个共存模块执行某些内存操作而具有不正确的行为。下面的示例代码片段也可以说明这种场景。
char *name = (char *) malloc(11); 
// Assign some value to name
memcpy ( p,name,11); // Problem begins here
在本例中,memcpy 操作尝试将 11 个字节写到 p,而后者仅被分配了 10 个字节。
作为良好的实践,每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。一般情况下,memcpy 函数将是用于此目的的检查点。
内存读取越界
内存读取越界 (overread) 是指所读取的字节数多于它们应有的字节数。这个问题并不太严重,在此就不再详述了。下面的代码提供了一个示例。
char *ptr = (char *)malloc(10);
char name[20] ;
memcpy ( name,ptr,20); // Problem begins here
在本例中,memcpy 操作尝试从 ptr 读取 20 个字节,但是后者仅被分配了 10 个字节。这还会导致不希望的输出。
内存泄漏
内存泄漏可能真正令人讨厌。下面的列表描述了一些导致内存泄漏的场景。
重新赋值
我将使用一个示例来说明重新赋值问题。
char *memoryArea = malloc(10);
char *newArea = malloc(10);
memoryArea 和 newArea 分别被分配了 10 个字节,它们各自的内容如图 4 所示。如果某人执行如下所示的语句(指针重新赋值)……
memoryArea = newArea;
则它肯定会在该模块开发的后续阶段给您带来麻烦。
在上面的代码语句中,开发人员将 memoryArea 指针赋值给 newArea 指针。结果,memoryArea 以前所指向的内存位置变成了孤立的。它无法释放,因为没有指向该位置的引用。这会导致 10 个字节的内存泄漏。
要避免内存相关的问题,良好的实践是:
始终结合使用 memset 和 malloc,或始终使用 calloc。
每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。
在对指针赋值前,要确保没有内存位置会变为孤立的。
每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应首先遍历子内存位置并从那里开始释放,然后再遍历回父节点。
始终正确处理返回动态分配的内存引用的函数返回值。
每个 malloc 都要有一个对应的 free。
确保您不是在访问空指针。

4.如何避免 android内存泄漏


  至少在T-Mobile G1上Android应用在堆上分配的内存大小被限制16MB以内。对于手机来说,这是个不小的内存,但是这仍然远远不能满足一些开发者的需求。但是,即使你不打算使用所有的内存空间,你也应该尽可能地少用内存,从而使得其他应用能够运行而不是被杀掉。因为Android能够在内存中保持的应用越多,那么用户切换应用的速度就会越快。作为我工作的一部分,我在做android应用开发的时候也会陷入内存泄漏的问题中,大多数时候内存的泄漏都是由于犯了相同的错误:长期持有了一个Context的引用。
Android上 ,Context可以用于很多操作,但是大部分时候是用来加载以及使用资源。这就是为什么所有的widgets在他们的构造函数中接受一个Context参数。在一般的android应用中,你通常有两种Context:分别是Activity和Application。通常的,当我们的类和方法需要使用到context时,我们传递的是Activity这个context:
[java] view plain copy
@Override 
protected void onCreate(Bundle state) { 
 super.onCreate(state); 
 
 TextView label = new TextView(this); 
 label.setText("Leaks are bad"); 
 
 setContentView(label); 

这意味着views拥有一个对整个activity的引用,也就是引用了你的activity所拥有的一切;通常的,这指的是完整的视图层级结构以及所有它的资源。因此,如果你泄露了一个Context(“ 泄漏 ”意味着你保持着它的一个引用,从而使它不能被垃圾回收机制回收),就意味着你泄漏了很多的内存。如果你不小心, 泄漏一 个activity的所有资源真的非常容易。
当 屏幕的方向发生改变的时候,系统默认将会销毁当前的activity并且创建一个新的activity同时保持着原有的状态。在做这个的时候,Android会从资源重新加载应用的UI。现在,想象一下你写了一个应用,这个应用有一张很大的bitmap。你不想再每一次旋转的时候重新加载它。最简单的方法让bitmap持续作用而不随每一个方向而重新加载 ,就是把它放进一个静态域:
[java] view plain copy
private static Drawable sBackground; 
 
@Override 
protected void onCreate(Bundle state) { 
 super.onCreate(state); 
 
 TextView label = new TextView(this); 
 label.setText("Leaks are bad"); 
 
 if (sBackground == null) { 
 sBackground = getDrawable(R.drawable.large_bitmap); 
 } 
 label.setBackgroundDrawable(sBackground); 
 
 setContentView(label); 

这段代码很快,但是错误也很严重:它泄漏了第一个activity,这个在第一次屏幕改变时被创建的activity。当一个Drawable被关联到一个view上,这个view就相当于在drawable上设置的一个回调。在上面的代码片段中,这表示drawable有一个TextView的引用,而这个TextView又拥有一个activity的引用(Context),activity依次引用了几乎所有的东西(取决于你的代码)。
这个例子展示了一个最简单的Context 泄漏的情况,你可以在Home screen 的源码中看到我们是如何解决这个问题的( 查找unbindDrawables() 方法) ,这就是当activity 被销毁的时候将drawables 的回调设为null 。有趣的是,你可能创造出一系列context泄漏的情况有很多,这非常糟糕。他们会是你很快内存溢出。
有两种简单的方法来避免context 相关的内存泄漏。最显著地一个是避免context 逃出他自己的范围之外。上面的例子就展示了使用静态引用的情况,而内部类和他们对外部类的的隐式引用也是同样危险的。第二种方法是使用Application context 。这个context 的生存周期和你的应用的生存周期一样长,而不是取决于activity 的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context ,记得使用application 对象。你可以通过调用Context.getApplicationContext() or Activity.getApplication() 来获得。
总而言之,想要避免context 相关的内存泄漏 ,记住以下几点:
· 不要对activity 的context 长期引用( 一个activity 的引用的生存周期应该和activity 的生命周期相同)
· 试着使用关于application的 context 来替代和activity相关的context
· 如果一个acitivity 的非静态内部类的生命周期不受控制,那么避免使用它;使用一个静态的内部类并且对其中的activity 使用一个弱引用。解决这个问题的方法是使用一个静态的内部类,并且对它的外部类有一WeakReference,就像在ViewRoot中内部类W所做的就是这么个例子。
· 垃圾回收器不能处理内存泄漏的保障。

5.c#程序如何避免内存泄漏


  通常来说很少发生真正底层的memory leak,更多的是由于编程经验不足导致内存浪费,资源得不到释放。具体表现为持续增加的内存消耗。
  日常coding时请注意以下几点:
  老生常谈的,非托管资源请在使用后释放资源。
  涉及stream时请务必小心,搞清楚它应该和实际在哪里被关闭,尤其是缓冲区设置的比较大的时候。
  .NET体系中有弱引用(weak reference)概念,请注意此类对象的生命周期,必要时加以干预。
  涉及线程和task时需要格外注意。管理不当的线程和task以及其持有的成员都是灾难之源。
  谨慎使用封闭的三方库。你看不到代码也控制不了它们的行为。如果有可能请尽量选择开源库,一旦发生问题方便调试和修改。
  经常检查自己的代码的圈复杂度,复杂度过高时容易引起难以察觉的内存问题。
  善用工具。试一下Ants Memory Profiler,绝大多数情况都能直接反编译并定位到问题。嗯,Resharper的profiler也可以一用。
  暂时就这么多。如有不熟悉的概念请google。

以上就是关于「如何避免内存泄露」的全部内容,本文讲解到这里啦,希望对大家有所帮助。如果你还想了解更多这方面的信息,记得收藏关注本站~

【文♂章①来自Win10系统之家www.ghoSt580.neT,不得自行转载,违者必追究!】

相关文章

  • 如何避免内存泄露

    如何避免内存泄露

    1.什么是内存泄漏如何避免内存泄漏可以分为4类:1.常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。2.偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才...
  • win7系统如何清理垃圾释放内存

    win7系统如何清理垃圾释放内存

    1.win7怎么深度清理c盘垃圾清理Win7/Win8/win10如何深度清理c盘垃圾让系统保持良好的运行状态具体方法如下:1、对C盘单击右键—属性,出来如下画面,单击磁盘清理按钮;2、然后系统会自动检测扫描可清理的垃圾,出现以下结...
  • win7电脑内存不够用如何增加虚拟内存

    win7电脑内存不够用如何增加虚拟内存

    1.我的电脑在运行时提示虚拟内存太低怎么增加虚拟内存虚拟内存内存在计算机中的作用很大,电脑中所有运行的程序都需要经过内存来执行,如果执行的程序很大或很多,就会导致内存消耗殆尽。为了解决这个问题,Windows中运...
  • 内存如何实现双通道

    内存如何实现双通道

    1.怎样设置双通道内存这个不用设置,只要将内存插在正确的插槽中就可以实现双通道内存的模式了,这些规范说明一般都是都在主板的说明上有详细的说明的,建议仔细阅读说明书,主板上一般会有两种颜色的内存卡槽,安装双通...