Java垃圾回收机制
开发工具与关键技术:myeclipse
撰写时间:2019年08月18日
一、垃圾回收机制的概念
垃圾回收(GC)是java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收任何对象引用的对象所占据的内存空间的一种机制
引用:如果Reference类型的数据中存储的 数值代表的是另外一个内存的起始地址,就称这块内存代表着一个引用
引用又分为强引用、软引用、弱引用、虚引用四种:
强引用(Strong Reference):如“Object obj=new Object()”,这类引用是java中最普遍的,只要强引用还存在,垃圾收集器就永远不会回收掉被引用的对象,不管内存是否管用
软引用(Soft Reference):它用来描述一种可能有用,但不是必须的对象,在系统内存不够用时,这类引用会在垃圾收集器下一次回收垃圾时被回收。
弱引用(Weak Reference):它用来描述非必须的对象,但它的强度比软引用更弱些,被弱引用关联的对象只能生存到下一次垃圾收集器回收垃圾之前,不论系统内存是否够用,都会回收掉只被弱引用关联的对象
虚引用(Phantom Reference):最弱的一种引用关系,完全不会对其生存空间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用的唯一目的就是希望能在这个对象被收集器回收时收到一个系统通知
二、垃圾回收机制的意义
垃圾回收可恶意有效的防止内存泄露(memory leak)、内存溢出(out of memory),有效的使用空闲的内存
内存泄露:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露似乎不会有大的影响,但内存泄露堆积后的后果就是内存溢出
内存溢出:指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
通俗讲就是一辆不能启动的车放在停车场,而我需要这个车位,但是我没办法移动这辆车,这就是内存泄露;就比如给你个小汽车的停车位(int),你非要停一辆高铁(Long),这就是内存溢出。
内存泄露大到一定程度会导致内存溢出。但是内存溢出不一定是内存泄露引起的
常见的内存泄露:
1.单例造成的内存泄露
由于单例的静态特性,使得它的生命周期和应用的生命周期一样长,如果一个对象已经不再需要使用了,而 单例对象还特有该对象的引用,就会使该对象不能被正确的回收,从而导致内存泄露
2.非静态内部类创建静态实例造成的内存泄露
非静态内部类默认会持有外部类的引用,而该非静态内部类又创建了一个静态的实例,该实例的生命周期和应用一样长,这就导致了该静态实例一直会持有该Activity的引用,从而导致Activity的内存资源不能被正确回收
3.Handler造成的内存泄露
Handler发送的消息在当前handler的消息队列中,如果此时activity finish掉了,那么消息队列的消息依旧会由handler进行处理,若此时handler声明为内部类(非静态内部类),内部类天然持有外部类的实例引用,那么就会导致activity无法回收,进而导致activity泄露
4.线程造成的内存泄露
如果任务在Activity销毁之前还未完成,那么将会导致Activity的内存资源无法被回收,从而造成内存泄露
5.资源未关闭,造成内存泄露
对于使用BraodcastReceiver, ContentObserver, File, Cursor, Stream, Bitmap 等资源,like在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄露
6.使用ListView时造成的内存泄露
构造Adapte时,没有使用缓存的convertView,Adapte中引用了Activity如何避免内存泄露
7.集合容器中的内存泄露
我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。
8.WebView造成的泄露
当我们不要使用WebView对象时,应该调用它的destory()函数来销毁它,并释放其咋占用的内存,否则长期占用的内存也不能被回收,从而造成内存泄露
常见的内存溢出:
1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收
3.代码中存在死循环或循环产生过多重复的对象实体
4.使用的第三方软件中的BUG;
5.启动参数内存值设定过小
内存溢出的解决方案:
一:修改JVM启动参数,直接增加内存
二:检查错误日志,查看“OutOfMemory”错误钱是否有其他异常或错误
三:对代码进行直查和分析,找出可能发生内存溢出的位置