zoukankan      html  css  js  c++  java
  • 引用类型与垃圾回收

    引用是与垃圾回收机制相关的 , 从JDK1.2开始 , 把引用划分为4种级别
    从而使程序能够更加灵活地控制对象的生命周期
    级别从高到低分别是 
    强引用 —> 软引用 —> 弱引用 —> 虚引用
     
     
     
    ↑ 强引用是作为基类的  , 另外三种引用类型都是它的子类
     
    (一) 强引用 ( StrongReference )
    强引用是最普遍的引用 , 如果一个对象具有强引用 , 那么垃圾回收器绝不会回收它
    如果具备强引用的对象过多 , Java虚拟机内存不足 , 就会抛出 OutOfMemoryError , 程序终止
     
    (二) 软引用 ( SoftReference )
    如果一个对象只具有软引用 , 当Java虚拟机内存空间足够时 , 垃圾回收器就不会回收它
    如果内存空间不足 , 这个对象就会被垃圾回收器回收掉
     
    软引用可以用来实现内存敏感的高速缓存
    也可以与一个引用队列 ( ReferenceQueue ) 联合使用 , 如果软引用所引用的对象被垃圾回收器回收
    Java虚拟机会把这个软引用加入到与之关联的引用队列当中
     
    (三) 弱引用 ( WeakReference )
    弱引用的对象拥有更短暂的生命周期 , 在垃圾回收器扫描它所管辖的内存区域的过程中
    一旦发现只具有弱引用的对象 , 不论内存空间是否足够 , 都会将其回收
    但是垃圾回收器是一个优先级很低的线程 , 因此不一定会很快发现那些只具有弱引用的对象
     
    弱引用同样可以与引用队列联合使用
     
    (四) 虚引用 ( PhantomReference )
    顾名思义 , 就是形同虚设 , 一个对象只持有虚引用 , 就与没有任何引用一样 , 随时会被垃圾回收器回收掉
    与弱引用的区别是 , 虚引用必须要与引用队列联合使用 
     

    实践
    --> 创建一个对象的弱引用 
    public class Mian<T extends Exception> {
         public static void main(final String[] args){
              Demo demo = new Demo();
               //创建一个弱引用
              WeakReference<Demo> weakRef = new WeakReference<Demo>(demo);
               //去掉该对象的强引用(此时它只具备一个弱引用)
              demo = null;
               //运行垃圾回收器
              System.gc();
               /*如果不请求执行垃圾回收,则不能保证在这个时候弱引用对象被回收*/
              
               //重新获得该对象的强引用
              demo = weakRef.get();
               if(demo == null ){
                   //如果该对象已经被垃圾回收器回收掉,那么获取到的就是null
                  System.out.println("The target is null" );
              } else {
                  System.out.println(demo.num );
              }
         }
    }
    
    class Demo {
         int num = 10;
    }

    执行的结果是当垃圾回收器启动的时候 , 弱引用对象已经被回收
    无法再次获取到强引用 ( get方法的返回值是null )
     
    软引用和虚引用的创建方式与此也是类似的
    在实际的程序设计当中 , 除了一般的强引用之外 , 软引用使用得相对较多
    因为软引用可以加速JVM对垃圾内存的回收速度 , 维护系统的运行安全 , 防止产生内存溢出的问题 

    附 : 使用软引用集合创建一个高速缓存器
    package com.system.util;
    
    import java.lang.ref.ReferenceQueue;
    import java.lang.ref.SoftReference;
    import java.util.Hashtable;
    
    import org.springframework.stereotype.Repository;
    /**
     * 数据库数据的高速缓存器
     * 使用软引用构成的集合实现
     * 在根据执行查询的时候,就把查询到的对象放入到缓存当中
     * 当该数据发生改变(被修改或删除),就从集合中移除该对象
     * 由于内存的限制,当集合中的数据过多时
     * 软引用对象会被垃圾回收器回收,避免内存溢出的情况
     * @author 41882
     *
     */
    @Repository
    public class DataCache {
        private Hashtable<String,DataRef> dataRefs;//缓存区
        private ReferenceQueue<Object> queue;//引用队列
        
        public DataCache() {
            dataRefs = new Hashtable<String,DataRef>();
            queue = new ReferenceQueue<Object>();
        }
        /**
         * 用于创建实例对象软引用的类
         * @author 41882
         *
         */
        private class DataRef extends SoftReference<Object> {
            public DataRef(Object obj,ReferenceQueue<Object> queue){
                super(obj,queue);
                String id = (String) ReflectUtils.getItemField(obj, "id");
                //缓存中的标识是该类名称与ID的组合
                this._key = obj.getClass().getSimpleName()+id;
            }
            private String _key;
        }
        /**
         * 从缓存区获取一个对象(如果缓存区没有该对象,则执行查询获得该对象)
         * @param <T>
         * @param id
         * @param clz
         * @return
         */
        @SuppressWarnings("unchecked")
        public <T> T getObject(Class<T> clz,String id){
            //从缓存中获取该实例的软引用
            DataRef ref = dataRefs.get(clz.getSimpleName() + id);
            if(ref == null){
                return null;
            } else {
                //由软引用获取强引用
                //如果该软引用对象已被回收,返回null
                return (T) ref.get();
            }
        }
        /**
         * 从缓存区当中移除一个对象
         * (通常在该对象被修改或删除的时候,就从缓存区移除该对象)
         * @param obj
         */
        public void removeObject(Object obj){
            String id = (String) ReflectUtils.getItemField(obj, "id");
            dataRefs.remove(obj.getClass().getSimpleName() + id);
        }
        /**
         * 从缓存区当中根据ID和类型移除多个对象
         * @param clz
         * @param ids
         */
        public void removeObject(Class<?> clz,String[] ids){
            if(ids != null && ids.length>0){
                for(String id : ids){
                    dataRefs.remove(clz.getSimpleName() + id);
                }
            }
        }
        /**
         * 清空缓存区
         */
        public void clearCache(){
            dataRefs.clear();
        }
        /**
         * 缓存数据
         * @param obj 需要执行缓存的对象
         */
        public void cacheData(Object obj) {
            cleanQueue();
            DataRef ref = new DataRef(obj,queue);
            dataRefs.put(obj.getClass().getSimpleName() + ReflectUtils.getItemField(obj, "id"), ref);
        }
        
        /**
         * 清除已经被回收的软引用对象
         */
        private void cleanQueue(){
            DataRef ref = null;
            while((ref=(DataRef) queue.poll()) != null) {
                dataRefs.remove(ref._key);
            }
        }
    }
  • 相关阅读:
    如何在Oracle官网下载java的JDK最新版本和历史版本
    屏幕录制专家【Bandicam】
    Bandicam下载 + 破解
    华为荣耀7i手动更改DNS,提高网页加载速度
    SQL中使用GROUP BY注意事项
    JavaScript数据类型判断
    React.lazy和Suspense组合实现组件懒加载
    使用React+TypeScript构建自己的组件库
    leetcode-0101 对称二叉树
    leetcode-0543 二叉树的直径
  • 原文地址:https://www.cnblogs.com/programInit/p/6363146.html
Copyright © 2011-2022 走看看