内存泄露是什么引起的

内存泄露是什么引起的,第1张

内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。

内存泄漏形象的比喻是" *** 作系统可提供给所有进程的存储空间正在被某个进程榨干",最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以"内存泄漏"是从 *** 作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。

内存泄漏或者是说,资源耗尽后,系统会表现出什么现象啊

cpu资源耗尽:估计是机器没有反应了,键盘,鼠标,以及网络等等。这个在windows上经常看见,特别是中了毒。

进程id耗尽:没法创建新的进程了,串口或者telnet都没法创建了。

硬盘耗尽: 机器要死了,交换内存没法用,日志也没法用了,死是很正常的。

内存泄漏或者内存耗尽:新的连接无法创建,free的内存比较少。发生内存泄漏的程序很多,但是要想产生一定的后果,就需要这个进程是无限循环的,是个服务进程。当然,内核也是无限循环的,所以,如果内核发生了内存泄漏,情况就更加不妙。内存泄漏是一种很难定位和跟踪的错误,目前还没看到有什么好用的工具(当然,用户空间有一些工具,有静态分析的,也会动态分析的,但是找内核的内存泄漏,没有好的开源工具)。

内存泄漏和对象的引用计数有很大的关系,再加上c/c++都没有自动的垃圾回收机制,如果没有手动释放内存,问题就会出现。如果要避免这个问题,还是要从代码上入手,良好的编码习惯和规范,是避免错误的不二法门。

一般我们常说的内存泄漏是指堆内存的泄漏。

堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。

应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。

1、资源释放问题

。 Android 程序代码的问题,长期保持某些资源,如 Context、Cursor、IO 流的引用,资源得不到释放造成内存泄露。

2、对象内存过大问题

保存了多个耗用内存过大的对象(如 Bitmap、XML 文件),造成内存超出限制。

3、static 关键字的使用问题

static 是 Java 中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所 以用 static 修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context 的情况最 多),这时就要谨慎对待了。

public class ClassName { private static Context mContext; //省略 }

1

1

以上的代码是很危险的,如果将 Activity 赋值到 mContext 的话。那么即使该 Activity 已经 onDestroy,但是由 于仍有对象保存它的引用,因此该 Activity 依然不会被释放。

我们举 Android 文档中的一个例子。

private static Drawable sBackground;

@Override protected void onCreate(Bundle state) {

superonCreate(state);

TextView label = new TextView(this); //getApplicationContext labelsetText("Leaks are bad");

if (sBackground == null) {

sBackground = getDrawable(Rdrawablelarge_bitmap);

}

labelsetBackgroundDrawable(sBackground); setContentView(label);

}

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

sBackground 是一个静态的变量,但是我们发现,我们并没有显式的保存 Context 的引用,但是,当 Drawable 与 View 连接之后,Drawable 就将 View 设置为一个回调,由于 View 中是包含 Context 的引用的,所以,实际 上我们依然保存了 Context 的引用。这个引用链如下: Drawable->TextView->Context 所以,最终该 Context 也没有得到释放,发生了内存泄露。

针对 static 的解决方案

① 应该尽量避免 static 成员变量引用资源耗费过多的实例,比如 Context。

② Context 尽量使用 ApplicationContext,因为 Application 的 Context 的生命周期比较长,引用它不会 出现内存泄露的问题。 ③ 使用 WeakReference 代替强引用。比如可以使用 WeakReference mContextRef;

4、线程导致内存溢出

线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。

public class MyActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {

superonCreate(savedInstanceState);

setContentView(Rlayoutmain);

new MyThread()start();

}

private class MyThread extends Thread{

@Override

public void run() {

superrun(); //do somthing while(true)

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

1

2

3

4

5

6

7

8

9

10

11

12

13

14

这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设 MyThread 的 run 函数是一个很费 时的 *** 作,当我们开启该线程后,将设备的横屏变为了竖屏,一 般情况下当屏幕转换时会重新创建 Activity,按照我 们的想法,老的 Activity 应该会被销毁才对,然而事实上并非如此。 由于我们的线程是 Activity 的内部类,所以 MyThread 中保存了 Activity 的一个引用,当 MyThread 的 run 函 数没有结束时,MyThread 是不会被销毁的,因此它所引用的老的 Activity 也不会被销毁,因此就出现了内存泄露的 问题。有些人喜欢用 Android 提供的 AsyncTask,但事实上 AsyncTask 的问题更加严重,Thread 只有在 run 函数不结 束时才出现这种内存泄露问题,然而 AsyncTask 内部的实现机制是运用了 ThreadPoolExcutor,该类产生的 Thread 对 象的生命周期是不确定的,是应用程序无法控制的,因此如果 AsyncTask 作为 Activity 的内部类,就更容易出现内存 泄露的问题。

针对这种线程导致的内存泄露问题的解决方案:

第一、将线程的内部类,改为静态内部类(因为非静态内部类拥有外部类对象的强引用,而静态类则不拥有)。

第二、在线程内部采用弱引用保存 Context 引用。

以上就是关于内存泄露是什么引起的全部的内容,包括:内存泄露是什么引起的、哪些情况会内存泄漏、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9445780.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-28
下一篇 2023-04-28

发表评论

登录后才能评论

评论列表(0条)

保存