Java 垃圾回收机制
在Java中,JVM负责内存动态分配和垃圾回收的问题。Java的对象必须要有引用才能被使用,也就是说如果要操作对象,必须通过引用来进行。如果一个对象唯一的引用变量死了(随着堆栈块一起解散),对象就会被认定为可被垃圾回收(Garbage Collection)的。没有被引用的对象,是没有存在意义的,因为没有人知道它的地址,无法调用它,它的存在只会浪费空间。 目前内存的动态分配和内存回收技术已经相当成熟,但还是需要了解GC和内存分配,这样当需要排查各种内存溢出、内存泄漏问题时,当GC成为系统达到更高并发量的瓶颈时,需要对这些自动化的技术实施必要的监控和调节。 判断对象是否可回收 最简单的方法是通过引用计数(reference counting)来判断一个对象是否可以被回收。不失一般性,如果一个对象没有任何引用与之关联,那么这个对象就被判定为可被回收的对象了。这种方式实现简单,而且效率较高,但是它无法解决对象间循环引用的问题,因此在Java中并没有采用这种方式(Python采用的是引用计数法)。 主流的商用程序语言(Java,C#,Lisp)的主流实现中,使用可达性分析(reachability analysis)来判定对象是否存活。 使用一些列GC Root对象作为起始点,从这些节点开始往下沿着引用链搜索,如果GC Root到某个对象无法通过任何引用链项链,则该对象会被标记一次, 并且进行一次筛选, 筛选的条件是此对象是否有必要执行finalize()方法. 当对象没有覆盖finalize()方法, 或者该方法已经被JVM调用过, JVM都会视之为没有必要执行finalize()。 如果该对象被判定为有必要执行finalize()方法, 那么这个对象会被放置在F-Queue队列中, 并在稍后由一个由JVM自动建立的, 低优先级的Finalizer线程去执行. 执行只是触发该方法, 但不会等待它结束, 因为可能会有执行缓慢或者死循环等特殊情况 稍后GC会动F-Queue里的对象进行第二次标记, 如果对象要在finalize()中避免被消灭, 只需要重新与引用链上的任何一个对象建立关联即可(finalize()的优先级较低), 这样第二次标记时它将不会被考虑. 否则就只能被回收. 要注意, 任何一个对象的finalize()只会被系统自动调用一次, 下次再GC时不会再执行, 也就是只有一次自救机会. 在Java中,可作为GC Roots的对象包括: 虚拟机栈(栈帧中的本地变量表)中引用的对象。 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中native方法引用的对象 引用 引用分为强引用,软引用,弱引用,虚引用。根据不同引用,有不同的GC回收策略。 强引用:类似Object obj = new Object();这种, 垃圾回收器永远不会回收他们 软引用:非必须引用,内存溢出之前进行回收. 如果这次回收后内存还不足,才会抛出内存溢出异常 Object obj = new Object(); SoftReference<Object> sf = new SoftReference<Object>(obj); obj = null; sf.get();//有时候会返回null 软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。 弱引用:非必须引用, 强度比软引用更弱. 当GC工作时, 无论当前内存是否足够, 都会回收掉只有弱引用关联的对象. Object obj = new Object(); WeakReference<Object> wf = new WeakReference<Object>(obj); obj = null; wf....