第一条:考虑用静态工厂方法代替构造器。
第二条:遇到多个构造器参数时要考虑用构造器。
第三条:用私有构造器或者枚举类型强化Singleton属性。
第四条:通过私有构造器强化不可实例化的能力。
第五条:避免创建不必要的对象。
String s=new String("abcd"); //Don't do this.
改进后的版本:
String s="abcd"; //只有一个String实例。
构造器在每次被调用是都会创建一个新的对象,而静态工厂方法则从不要求这样做。
除了重用不可变的对象之外,也可以重用那些已知不会被修改的可变对象。
第六条:消除过期对象的引用。
如果一个栈先是增加,然后收缩,那么从栈中弹出来的对象将不会被当做垃圾回收,即使使用栈的程序不再引用执行对象。这是因为栈内部维护着对这些对象的过期引用。所谓过期引用就是永远不会被解除的引用。这类问题的修复方法很简单:一旦对象引用已经过期,只需清空这些引用即可。
内存泄露的另一个常见来源是缓存。
内存泄露的第三个常见来源是监听器和其回调。如果实现了一个API,客户端咋这个API中注册回调,却没有显示地取消注册,除非采取某些动作,否则它们就会积聚。确保回调被立即当做垃圾回收的最佳方法是只保留它们的弱引用,例如,只将它们保存在WeakHashMap中的键。
第七条:避免使用终结方法。
注重时间的任务不应该由终结方法来完成。例如,用终结方法来关闭已经打开的文件,这是严重错误的,因为打开文件的描述符是一种很有限的资源。由于JVM会延迟执行终结方法,所以大量的文件会保留在打开状态,当一个程序再不能打开文件时,它可能运行失败。
不应依赖终结方法来更新重要的持久状态。例如,依赖终结方法来释放共享资源(比如数据库)上的永久锁,很容易让整个分布式系统垮掉。
使用终结方法有一个非常严重的性能损失。
如果类的对象中封装的资源(例如文件或者线程)确实需要终止,只需提供一个显示的终结方法,并要求该类的客户端在每个实例不再有用的时候调用这个方法。该实例必须记录下自己是否已经被终止:显示的终止方法必须在一个私有域中记录下“该对象已经不再有效”。如果这些方法是在对象已经终止之后被调用,其他方法就必须检查这个域,并抛出IllegalStateException异常。显示终结方法通常与try-finally结构结合起使用。