3.1 对象创建
对象的创建是一个非常昂贵的工作,而由于对象的创建而导致经常性的垃圾收集则是一个更加消耗时间和CPU的操作。我们在编码时,应当尽量的减少对象的创建。不要在经常被执行的代码中创建对象;使用集合对象时最好预先分配其大小;当一个class的多个实例都需要获取某个对象时,最好能标记那个对象static;当不需要stack trace时尽可能的重用异常实例等等都能很有效的避免对象创建而导致的额外的开销。下面是一些常用的有效的策略:
1) 对象池技术
在Java中开发一个普遍性的对象池架构可以更好地利用资源,并可以使对象创建的成本降到最小。大多数人对直接或间接运用对象池来连接一个数据库都很熟悉。但通常你也可以将对象放入对象池中从而节省重要的资源、提高程序的效率并控制对不充足资源的访问。出于对设计、成本或性能的考虑,放入对象池中的对象通常是有限的。它们或者是初始化成本很高的对象,或者是很少用的对象。运用对象池我们可以管理竞争性客户端对有限的对象集的访问。
对象池主要是可以更好地运用你的资源。例如,设想有相当多的客户要有效运用很少的数据库连接或网络连接。通过限制对对象的访问(只在客户端需要的时候才能访问对象),你就可以释放资源,让其它客户端使用。通过对象池提高对象的利用率通常可以提高系统的性能。
你可以使用对象池使初始化的成本达到最小。典型的例子包括数据库、网络连接和线程。这样的连接通常需要很多时间来初始化。一旦创建了这些连接,你就可以重用它们,从而极大地节省了成本。因此,你可以将初始化成本很高(从时间、内存或其它资源方面考虑)的对象放入对象池中。例如,大多数容器都将EJB放入对象池中,从而避免重复的资源分配和状态初始化。
一个设计良好的对象池架构具有普遍性,它适合不同应用程序的需要。可以让你控制对象池的容量、对象填充策略和对象状态。它可以极大地提高你的应用程序的效率,不管从速度方面考虑,还是从资源利用率方面考虑,该架构都可以提供这样的好处。
在这里,给大家推荐一个开源的项目Commons-Pool(http://jakarta.apache.org/commons/pool/),我还没来得及研究,谁用过了,感觉好的,麻烦告诉我一下,谢谢!
2) ThreadLocal技术
使用此技术获取线程绑定的带状态的单例对象。
3) 单例模式
通过单例模式或使定义对象static来使得对象的实例只能有一个并被其他对象所共享。
4) 枚举常量
使用整数取代字符串作为枚举常量,比如FEMALE和MALE我们可以用整数1和2来替代。这样将带来速度上和内存上的优势。
5) 使用SoftReference,WeakReference和PhantomReference引用类
引用类的主要功能就是能够引用仍可以被垃圾收集器回收的对象。在引入引用类之前,我们只能使用强引用(Strong Reference)。例如obj这个引用将引用堆中存储的一个对象,只要obj引用还存在,垃圾收集器就永远不会释放用来容纳该对象的存储空间。当obj超出范围或被显式指定为null时,垃圾收集器就认为没有对这个对象的其他引用,也就可以收集它了。然而还需要注意一个重要的细节:仅凭对象可以被收集并不意味着垃圾收集器的一次指定运行就能够回收它。由于各种垃圾收集算法不同,某些算法会更频繁地分析生存期较短的对象,而不是较老、生存期较长的对象。因此,一个可供收集的对象可能永远也不会被回收。如果程序在垃圾收集器释放对象之前结束,这种情况就可能会出现。因此,概括地说,你永远无法保证可供收集的对象总是会被垃圾收集器收集。
让我们来看看一些术语和定义:
强可及对象(Strongly Reachable):可以通过强引用访问的对象。
软可及对象(Softly Reachable):不是强可及对象,并且能够通过软引用访问的对象。
弱可及对象(Weakly Reachable):不是强可及对象也不是软可及对象,并且能够通过弱引用访问的对象。
虚可及对象(Phantomly Reachable):不是强可及对象、软可及对象,也不是弱可及对象,已经结束的,可以通过虚引用访问的对象。
清除:将引用对象的refernce域设置为null,并将引用类在堆中引用的对象声明为可结束的。
SoftReference类:SoftReference类的一个典型用途就是用于内存敏感的高速缓存。SoftReference的原理是:在保持对对象的引用时保证在JVM报告内存不足情况之前清楚所有的软引用。关键之处在于,垃圾收集器在运行时可能会(也可能不会)释放软可及对象。对象是否被是否取决于垃圾收集器的算法以及垃圾收集器运行时可用的内存数量。
WeakReference类:WeakReference类的一个典型用途就是规范化映射(Canonicalized Mapping)。另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说,弱引用也比较有用。关键之处在于,垃圾收集器运行时如果碰到了弱可及对象,将释放 WeakReference 引用的对象。然而,请注意,垃圾收集器可能要运行多次才能找到并释放弱可及对象。
PhantomReference类:PhantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行 pre-mortem 清除操作。 PhantomReference 必须与 ReferenceQueue 类一起使用。需要 ReferenceQueue 是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时, PhantomReference 对象就被放在它的 ReferenceQueue 上。将 PhantomReference 对象放在 ReferenceQueue 上也就是一个通知,表明 PhantomReference 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。
在某些场合引用类还是很有用的,具体可以参考文章Java2引用类使用指南(http://www-128.ibm.com/developerworks/cn/java/j-refs/index.html)。
6) 尽可能少的减少不必要对象的生成
尽可能减少在循环中创建对象,使用StringBuffer而不要使用String来做连接操作等等。
7) 改变对象的创建时机
通过提前创建对象或延迟到使用时再创建对象,来做到性能优化和避免创建过多的对象。