对象引用分析

对象的三种状态:

可达的

从根节点可以触及到这个对象

可复活的

一旦所有引用被释放,就是可复活状态

因为在finalize()中可能复活该对象

不可达的

在finalize()后,可能会进入不可触及状态

不可达的对象不可能复活

可以回收

引用标记

Java虚拟机提供自动内存管理机制。在GC中,没用的对象,内存是要回收的。如何高效判断对象存活是个重要的问题。

引用计数法

此算法计算对象被引用的次数。引用失效就减一。当对象引用个数为0时表示不被引用。引用计数法,失效简单,效率高是个不错的算法。但Java虚拟机并不使用引用计数器算法作为对象的引用标记。原因是不能处理对象互相引用问题。如A?B,两个对象互相引用。AB对象缺没有被引用,形成引用孤岛。

可达性分析算法

可达性分析算法,是通过一系列被称为"GC Roots"的对象作为起点,从起点开始的引用链都没有被链接,表示对象是不可达的。

Java中GC Roots对象:

  1. 虚拟机栈中引用的对象
  2. 方法区类静态属性引用的对象
  3. 方法区常量引用的对象
  4. 本地方法栈引用的对象

支配树

对象的引用类型

对象分为被引用和不被引用,但这并不利于描述数据的重要级别。对于不同的场景,提供最优的对象引用策略,引用类型细分是有必要的。

对于计算过程的对象,当然在运算结束之前都不应该被垃圾回收。

对于频繁使用数据,希望不必重复读写,作为缓存。尽可能的不要垃圾回收。

对于不重要的对象,希望垃圾回收的时候直接回收,不用关心是否被引用。

Java中所有特殊引用类型的父类。引用类型不会被直接回收(会有特殊策略)。这些引用类型多被用于缓存,缓存的目的是对象有条件的垃圾回收。Reference并不会产生对象。对象被Reference包装,成为引用对象。如果引用包装的对象没被直接使用(即强引用),也不会被GC直接垃圾回收。如果引用的对象在使用,跟普通对象没有确保是不会被垃圾回收的。引用的多种策略是在对象没有被使用的情况下发生的。

应用类型主要有三个方法:

  • Get()获取包装对象
  • Clear()清空
  • Enquene()注册对象被回收回调

强引用(StrongReference)

强引用是普遍引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。如下:

这是一个常见的方法片段。StrongRef是自定义类。Object o=new Object();类型的都是强引用。此时o叫实例,而不能说o是对象。实例在栈中,对象在堆中,操作实例实际上是通过实例的指针间接操作对象。多个实例可以指向同一个对象。sRef指向的对象的作用范围只在这个方法体中。

方法执行完,生命周期结束,所以sRef指向空没有意义,这在虚拟机中会被优化。但非局部变量,则不同。

强引用在ArrayList的实现源代码:

ArrayList中用于保存数据的elementData数组。在调用clea()方法实际上是让数组中每个元素指向空,并不释放内存。对于集合的多次使用,节约内存申请和释放,并且如果元素个数差别不大,也省去了数组动态扩张、数组复制的时间。

?注:在ArrayList类中定义了一个私有的变量elementData数组,在调用方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型特别适用,这样就可以及时释放内存。

  1. 软引用(SoftReference)

    软引用多用在高效缓存,不会轻易被垃圾回收。软引用内存回收发生在,GC完成后内存还不足的情况。保证回收发生在抛出OutOfMemoryError之后。一般来讲,是二次GC。如果内存充足,软引用是不会被垃圾回收的。


  2. 弱引用(WeakReference)

    弱引用对象在垃圾回收时会被回收。

    用弱引用实现的API

    虚引用(PhantomReference)


    "虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

    虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

    其它API

    ReferenceQueue,一种当 weak, soft, phantom的referent被GC回收后,提供事件回调的接口。需要在实例化三大reference时,通过构造函数传入,phantom reference是强制需要传入的,weak和soft可不传。

    回调过程:

    GC回收referent后(phantom是在回收前,finalize后),将reference enqueue到RQ中,程序通过调用RQ的remove方法来感知reference被GC回收的事件。
    remove方法是阻塞的,当没有referent被回收时(GC未调用enqueue),remove方法会一直挂起线程,当有referent被回收时,该方法返回 referent对应的reference对象。
    同样,RQ也提供了一个非阻塞的方法 poll,但这样就做不到实时回调了。

时间: 2024-10-24 19:39:25

对象引用分析的相关文章

Android中View绘制流程以及invalidate()等相关方法分析

前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measure).是否重新需要安置视图的位置(layout).以及是否需要重绘 (d

Hadoop之HDFS原理及文件上传下载源码分析(上)

HDFS原理 首先说明下,hadoop的各种搭建方式不再介绍,相信各位玩hadoop的同学随便都能搭出来. 楼主的环境: 操作系统:Ubuntu 15.10 hadoop版本:2.7.3 HA:否(随便搭了个伪分布式) 文件上传 下图描述了Client向HDFS上传一个200M大小的日志文件的大致过程: 首先,Client发起文件上传请求,即通过RPC与NameNode建立通讯. NameNode与各DataNode使用心跳机制来获取DataNode信息.NameNode收到Client请求后,

Arrays源码分析

package java.util; import java.lang.reflect.Array; import java.util.concurrent.ForkJoinPool; import java.util.function.BinaryOperator; import java.util.function.Consumer; import java.util.function.DoubleBinaryOperator; import java.util.function.IntBi

对Binder的浅显分析及AIDL的使用

通常情况下,作为一个android开发者不会直接接触到Binder,但Binder作为ipc机制最关键的一个环节,我们很有必要去了解他.其实在不知不觉中,大家肯定和Binder打过交道,比如我们bindService的时候,客户端会获取到一个远程服务器发送回来的Binder对象,通过操作这个对象我们可以获取服务端的数据或者执行某些服务端的操作.再比如,我么在获取各种系统服务的时候,Binder是作为serviceManager连接各种manager(windowManager.....)的桥梁.

Android视图SurfaceView的实现原理分析

附:Android控件TextView的实现原理分析 来源:http://blog.csdn.net/luoshengyang/article/details/8661317 在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面.由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制.又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输

未将对象引用到实例

对象为null时调用给对象的属性或方法 "未将对象引用到实例"是很多像我一样的初学者经常遇到的一个问题,常常令人烦恼不已,那么这个问题是怎么发生的呢?先给大家看一张图,我们从这张图入手来分析这个错误造成的原因. 可能很多人看到这样的代码会觉得可笑:"能写出这样的代码,看来此人的智商已"超越"人类的范畴了!" 但是就是有某些内裤外穿的超人叔叔经常不间歇性的写出这样的代码.遇到这样的问题. 从这张图上我们很容易看出Too.f1.array[i]是为n

Java之ThreadLocal原理分析

简介 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序.当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本.从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思.所以,在Java中编写线程局部变量

转 kobject结构体分析

转载自:http://blog.csdn.net/zhoujiaxq/article/details/7646050 未知作者,以及源地址 ,敬请谅解. kobject是组成设备device.驱动driver.总线bus.class的基本结构. 如果把前者看成基类,则后者均为它的派生产物. device.driver.bus.class构成了设备模型,而kobject内嵌于其中,将这些设备模型的部件组织起来,并形成了sysfs文件系统.kobject就是device.driver.bus.cla

android分析之消息处理

前序:每个APP对应一个进程,该进程内有一个ActivityThread的线程,称为主线程(即UI主线程),此外,还有其他线程,这个再论. android的消息系统分析. 每个Thread只对应一个Looper 每个Looper只对应一个MessageQueue 每个MessageQueue中有N个Message 每个Message中最多指定一个Handler来处理事件 一个Thread可以对应多个Handler Looper负责从消息队列中(MessageQueue)取出消息(Message/