EffectiveJava——创建和销毁对象3

第6条:消除过期对象

Java的内存管理相比C/C++更加简单,应为当对象用完后它们会被自动回收,但是支持垃圾回收的语言中,

很隐蔽的内存泄漏(无意识的对象保持)。

消除过期引用最好的方法就是让包含该引用的变量介绍其生命周期

内存泄漏另一个常见的来源是缓存

一旦你把对象引用放入到缓存中,它就很容易被遗忘,这就有可能造成内存泄漏

只要缓存之外存在对某个项的键的引用,该项就有意义,那么就可以使用WeakHashMap做缓存,缓存中的项过期后,它们会被自动删除,但是记住:只有当索要的缓存项的生命周期是有该键的外部引用而不是值决定时,WeakHashMap才有用处

LinkedHashMap的removeEldestEntry方法,可以实现在缓存的添加过程中顺便清理不需要的缓存。

public class One_cache {
    public static void main(String[] args) {
        FixSizeLinkedHashMap<String, String> linkedHashMap = new FixSizeLinkedHashMap<>();
        linkedHashMap.setMaxSize(3);
        linkedHashMap.put("aa", "bb");
        linkedHashMap.put("cc", "dd");
        linkedHashMap.put("ee", "ff");
        linkedHashMap.put("hh", "ii");
        linkedHashMap.put("jj", "kk");
        System.out.println(linkedHashMap);
    }


    public static class FixSizeLinkedHashMap<K, V> extends LinkedHashMap<K, V> {

        private int mMaxSize;

        public FixSizeLinkedHashMap() {
            mMaxSize = 10;
        }

        public void setMaxSize(int maxSize) {
            this.mMaxSize = maxSize;
        }

        /**
         * 如果Map的尺寸大于设定的最大长度,返回true,再新加入对象时删除最老的对象
         */
        @Override
        protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
            return size() > mMaxSize;
        }
    }
}

打印结果是:
{ee=ff, hh=ii, jj=kk}

监听器和回调也是发生内存泄漏常见来源

可以采用weak reference保存回调

第7条:避免使用终结方法

终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的,使用终结方法会导致行为不稳定,降低性能,以及移植性问题。

终结方法的缺点在于不能保证会被及时的执行,从一个对象变得不可达开始,到它的终结方法被执行,所花费的时间是任意长的,这意味着注重时间的任务不应该由它来完成,例如在终结方法中关闭已打开的文件是严重的错误,打开文件描述符是很有效的资源,由于jvm会延迟执行终结方法,所以大量文件会保留在打开状态。

  • **java语言规范甚至不保证终结方法会被执行,所以不应该依赖终结方法来更新重要的持久状态。例如释放共享资源。
    **
  • 在正常情况下,没有被捕获的异常将会导致线程的终止,并打印出栈轨迹,但是如果异常发生在终结方法中,则不会,甚至没有任何警告。

如果要释放资源,可以提供显示的是否资源的方法

如果要使用终结方法,子类在覆盖终结方法时,必须调用父类的终结方法,否则超类的终结方法将永远不会被调用。最好在finally{}中调用超类的终结方法

你可能感兴趣的:(对象)