垃圾回收机制
所谓的内存泄漏简单来说是不再用到的内存,没有及时释放,为了更好避免内存泄漏。其原理是:垃圾收集器会定期找出那些不在继续使用的变量,然后释放其内存。
垃圾回收方法
垃圾回收有两种方法:标记清除、引用计数。目前用的比较多得是标记清除。
标记-清除:
js中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
function test(){
var a = 10 ; // 被标记 ,进入环境
var b = 20 ; // 被标记 ,进入环境
}
test(); // 执行完毕 之后 a、b又被标离开环境,被回收。
12345
引用-计数:
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是 1。如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为 0 的值所占用的内存。
function test() {
var a = {}; // a指向对象的引用次数为1
var b = a; // a指向对象的引用次数加1,为2
var c = a; // a指向对象的引用次数再加1,为3
var b = {}; // a指向对象的引用次数减1,为2
}
123456
内存泄漏
内存泄露是指用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。即所谓内存泄漏。
常见的内存泄露造成的原因
1. 单例造成的内存泄漏
由于单例的静态特性使得其生命周期和应用的生命周期一样长,如果一个对象已经不再需要使用了,而单例对象还持有该对象的引用,就会使得该对象不能被正常回收,从而导致了内存泄漏。
示例:防止单例导致内存泄漏的实例
// 使用了单例模式
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}
123456789101112131415
2. WebView造成的泄露
当我们不要使用WebView对象时,应该调用它的destory()函数来销毁它,并释放其占用的内存,否则其长期占用的内存也不能被回收,从而造成内存泄露。
为WebView另外开启一个进程,通过AIDL与主线程进行通信,WebView所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。
3. 集合容器中的内存泄露
我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
解决方法:在退出程序之前,将集合里的东西clear,然后置为null,再退出程序。
如何避免内存泄漏?
平常养成良好的代码书写习惯,该销毁的对象要销毁比如destory啊 广播啊 ,涉及到要用到content上下文的优先考虑全局上线文对象。