目录
Java对象的大小
这里要使用的是lucene提供的专门用于计算堆内存占用大小的工具类:RamUsageEstimator
<dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>4.0.0</version> </dependency>
使用该第三方工具比较简单直接,主要依靠JVM本身环境、参数及CPU架构计算头信息,再依据数据类型的标准计算实例字段大小,计算速度很快,另外使用较方便。如果非要说这种方式有什么缺点的话,那就是这种方式计算所得的对象头大小是基于JVM声明规范的,并不是通过运行时内存地址计算而得,存在与实际大小不符的这种可能性。
常用API
//计算指定对象及其引用树上的所有对象的综合大小,单位字节 long RamUsageEstimator.sizeOf(Object obj) //计算指定对象本身在堆空间的大小,单位字节 long RamUsageEstimator.shallowSizeOf(Object obj) //计算指定对象及其引用树上的所有对象的综合大小,返回可读的结果,如:2KB String RamUsageEstimator.humanSizeOf(Object obj)
测试
public static void main(String[] args) { Object o = new Object(); //计算指定对象及其引用树上的所有对象的综合大小,单位字节 System.out.println(RamUsageEstimator.sizeOf(o)); //计算指定对象本身在堆空间的大小,单位字节 System.out.println(RamUsageEstimator.shallowSizeOf(o)); //计算指定对象及其引用树上的所有对象的综合大小,返回可读的结果,如:2KB System.out.println(RamUsageEstimator.humanSizeOf(o)); System.out.println("一个Interger对象大小为:"+RamUsageEstimator.sizeOf(new Integer(1))); System.out.println("一个String对象大小为:"+RamUsageEstimator.sizeOf(new String("a"))); System.out.println("一个char对象大小为:"+RamUsageEstimator.sizeOf(new char[1])); System.out.println("一个ArrayList对象大小为:"+RamUsageEstimator.sizeOf(new ArrayList<>())); System.out.println("一个Object对象大小为:"+RamUsageEstimator.sizeOf(new Object())); System.out.println("一个Long对象大小为:"+RamUsageEstimator.sizeOf(new Long(10000000000L))); } 结果: 16 16 16 bytes 一个Interger对象大小为:16 一个String对象大小为:48 一个char对象大小为:24 一个ArrayList对象大小为:40 一个Object对象大小为:16 一个Long对象大小为:24
对象引用类型
从高到低依次:
强引用(StrongReference)
软引用(SoftReference)
弱引用(WeakReference)
虚引用(PlantomReference)
强引用
就是我们一般声明对象是时虚拟机生成的引用,强引用环境下,JVM宁可抛出OOM(out of memory)异常也不会回收强引用所指向的对象,即GC(垃圾回收或垃圾收集)绝对不会回收强引用类型。由于GC绝不会回收强引用,所以它将可能导致内存泄漏。
例:
//object和str都是强引用 Object object = new Object(); String str = "hello"; String s = new String()
软引用
软引用用于描述一些还有用但并非必须的对象,一般被做为缓存来使用(比如网页缓存、图片缓存)。与强引用的区别是,软引用在垃圾回收时,虚拟机会根据当前系统的剩余内存来决定是否对软引用进行回收。如果剩余内存比较紧张,则虚拟机会回收软引用所引用的空间;如果剩余内存相对富裕,则不会进行回收。换句话说,虚拟机在发生OutOfMemory时,肯定是没有软引用存在的。
例:
SoftReference<String> sr = new SoftReference(new String("123")); System.out.println(sr.get());
注意
在垃圾回收器对这个Java对象回收前,SoftReference类所提供的get方法会返回Java对象的强引用,一旦垃圾线程回收该Java对象之后,get方法将返回null。所以在获取软引用对象的代码中,一定要判断是否为null,以免出现NullPointerException异常导致应用崩溃。
弱引用
弱引用用于实现一些规范化映射(WeakHashMap),其中key或者value当它们不再被引用时可以自动被回收。当你想引用一个对象,但是这个对象有自己的生命周期,你又不想介入这个对象的生命周期时,便可以用弱引用。同时弱引用也可以用来保存那些可有可无的缓存数据,和软引用一样,在内存充足时加速系统,在内存不足时便被系统回收。弱引用在系统GC时,只要一被发现,不管系统堆内存空间是否足够,都会将对象进行回收,一旦被回收便会被加入到相关联的引用队列中。但是,由于垃圾回收器的线程通常优先级很低,所以并不一定能很快发现持有弱引用的对象,所以弱引用的生命周期是从被创建到下一次GC发送之前。
例:
WeakReference<String> wr = new WeakReference(new String("123")); System.out.println(wr.get()); System.gc(); //通知JVM的gc进行垃圾回收 System.out.println(wr.get());
注意
第二个输出结果是null,这说明只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。不过要注意的是,这里所说的被弱引用关联的对象是指只有弱引用与之关联,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象(软引用也是如此)。
虚引用
虚引用又叫幽灵或幻影引用,主要用来跟踪对象被垃圾回收器回收清理的活动,提供比Java清理机制更灵活的处理方式。虚引用是所有引用类型中最弱的一个,如果一个对象拥有一个虚引用,那它便和没有被引用一样,随时可能被GC回收,而且GC在回收时会直接销毁持有该引用的对象,并把虚引用加入引用队列中。除此之外需要注意的一点是,当虚引用试图通过get()方法取得强引用时,无论强引用是否存在,总是会失败,即获得的返回值永远为null。
虚引用与软引用和弱引用的区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
例:将虚引用和引用队列结合使用,可以看到虚引用的对象被垃圾回收后,虚引用将被添加到引用队列
String str =new String("123"); ReferenceQueue rq=new ReferenceQueue(); WeakReference wr=new WeakReference(str); PhantomReference pr=new PhantomReference(str,rq); Object obj=wr.get(); System.out.println(obj); System.out.println(wr.get()); str=null; System.out.println(pr.get()); System.gc(); System.runFinalization(); System.out.println(rq.poll()==pr); //rq.poll()函数作用为检索并移除文件的头 //rq.poll(); System.out.println(rq.poll()==pr); 结果: 123 123 null false false
评论 (0)