一、背景
大家知道Java是运行在虚拟机上的高级语言,而对于虚拟机,其中有一个特别重要的功能就是垃圾回收器(GC),通过GC机制Java程序可以非常智能的对垃圾进行回收,从而实现非常智能的内存管理,而不用向C或C++一样需要十分谨慎的自己去处理内存问题,从而避免了很多不必要的麻烦。那么GC机制是如何实现的呢?作为GC工作的主战场JVM 的堆内存,是如何去处理那些过期或者在资源紧缺的情况下对对象的处理呢?下面就引出了一个概念,Java对象的引用级别。
二、Java 引用的类别
1 、强引用
只要程序通过 new 关键字创建了对象,那么垃圾回收期永远不会进行对对象的回收,除非是系统内存不够,即便如此,JVM也就只是抛出OutOfMemory()异常,当然如果对象的引用被释放后。这个对象将会被释放掉。那么如何清空这个对象的引用呢?对象的引用是存放在JVM的栈内存中,所以我们清空栈里面的引用自然就清除了这个对象所占用的内存空间。
2 、软引用
非必须引用,当内存资源不够即将溢出时,这个时候GC将会对对象的内存空间进行回收,从而避免内存溢出错误的发生。如何实现软引用:
Object obj = new Object();
SoftReference
obj = null ;
sf.get(); // 这个时候sf是obj对象的一个软引用,通过get()方法可以获取到这个对象,当内存不足的时候可能返回 null ;
使用场景:当用户需要实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除部分缓存数据,从真正的来源查询相关数据。
3 、弱引用
第二次垃圾回收时回收,不管当前内存资源是否充足,这就是传说中的躺枪吧。。。。 如何实现弱引用:
Object obj = new Object ();
WeakReference
obj = null ;
wf.get(); // 有的时候回返回null
wf.isEnQueued(); // 返回是否被垃圾回收器标记为即将回收的装状态
弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnqueued方法返回对象是否被垃圾回收器标记。
4、虚引用(幽灵引用)
obj = null ;
pf.isEnQueued();//返回对象是否已经被清理的状态
虚引用主要用于检测对象是否已经从内存删除。
虚引用是话语权级别最低的引用了,只要垃圾回收开始工作,那么虚引用就会被回收。 实现方式:
Object obj = new Object ();
PhantomReference
pf.get();//永远返回null
三 、开发实战
作为一个初级的Java开发工程师,可能永远不会考虑JVM的内存问题,但是偶尔大家可能还是会出现OutOfmemory 错误的情况,例如部署一个较大的Tomcat
web服务其实在这个时候大家不需要惊慌,通常我们可以配置Tomcat的配置文件增大内存,或者JVM的内存设置,同时我们还可以通过JVM的GC机制来对程序进行一
定的优化,例如使用软引用,可以一定程度的促进GC的回收,从而避免内存溢出的情况。
尤其是在Android程序的开发中,由于本身硬件资源的短缺,我们更加要学会是使用这些机制去优化我们的程序。
例如:1、图片加载的时候出现内存溢出的情况。
四 、扩展
JVM的GC机制固然智能,降低了程序员的开发难度,但是与此同时也造成一些额外的不良体验,JVM的垃圾回收器主要负责:分配内存,确保被引用的对象不被
回收以及不被引用的对象及时被清理。其实他是一项非常复杂而且耗时的操作,如果JVM花费过多的时间在垃圾回收上,势必会影响程序的性能。所以当GC器开
始工作的时候整个JVM的程序其实是会产生短暂暂停,也就是大家通常所说的卡顿现象。这也就是为什么Android手机不管内存升级到多大还是会产生卡顿的原因,
因为这是Android系统的语言特性,没有办法避免。当然随着技术的发展现在Android系统是越来越流畅,很多的JVM调优机制都可以让我们的程序运行的更加流畅,
用户几乎察觉不到卡顿的现象,其实从底层的原理上来讲只要我们促进GC器工作的间隔越小,工作时间越短,那么对于用户的体验就越好。