面向GC的Java编程
作者:网络转载 发布时间:[ 2014/6/20 11:21:20 ] 推荐标签:软件开发 java
七、对象池
为了减少对象分配开销,提高性能,可能有人会采取对象池的方式来缓存对象集合,作为复用的手段。
但是对象池中的对象由于在运行期长期存活,大部分会晋升到Old Generation,因此无法通过YoungGC回收。
并且通常……没有什么效果。
对于对象本身:
如果对象很小,那么分配的开销本来小,对象池只会增加代码复杂度。
如果对象比较大,那么晋升到Old Generation后,对GC的压力更大了。
从线程安全的角度考虑,通常池都是会被并发访问的,那么你需要处理好同步的问题,这又是一个大坑,并且同步带来的开销,未必比你重新创建一个对象小。
对于对象池,合适的场景是当池中的每个对象的创建开销很大时,缓存复用才有意义,例如每次new都会创建一个连接,或是依赖一次RPC。
比如说:
· 线程池
· 数据库连接池
· TCP连接池
即使你真的需要实现一个对象池,也请使用成熟的开源框架,例如Apache Commons Pool。
另外,使用JDK的ThreadPoolExecutor作为线程池,不要重复造轮子,除非当你看过AQS的源码后认为你可以写得比Doug Lea更好。
八、对象作用域
尽可能缩小对象的作用域,即生命周期。
如果可以在方法内声明的局部变量,不要声明为实例变量。
除非你的对象是单例的或不变的,否则尽可能少地声明static变量。
九、各类引用
java.lang.ref.Reference有几个子类,用于处理和GC相关的引用。JVM的引用类型简单来说有几种:
· Strong Reference,常见的引用
· Weak Reference,当没有指向它的强引用时会被GC回收
· Soft Reference,只当临近OOM时才会被GC回收
· Phantom Reference,主要用于识别对象被GC的时机,通常用于做一些清理工作
当你需要实现一个缓存时,可以考虑优先使用WeakHashMap,而不是HashMap,当然,更好的选择是使用框架,例如Guava Cache。
后,再次提醒,以上的这些未必可以对代码有多少性能上的提升,但是熟悉这些方法,是为了帮助我们写出更卓越的代码,和GC更好地合作。

sales@spasvo.com