一、释放不必要的引用:
代码持有了不需要的对象引用,造成这些对象无法被GC,从而占据了JVM堆内存。(使用ThreadLocal:注意在线程内动作执行完毕时,需执行ThreadLocal.set把对象清除,避免持有不必要的对象引用)
二、使用对象缓存池:
创建对象要消耗一定的CPU以及内存,使用对象缓存池一定程度上可降低JVM堆内存的使用。
三、采用合理的缓存失效算法:
如果放入太多对象在缓存池中,反而会造成内存的严重消耗, 同时由于缓存池一直对这些对象持有引用,从而造成Full GC增多,对于这种状况要合理控制缓存池的大小,避免缓存池的对象数量无限上涨。(经典的缓存失效算法来清除缓存池中的对象:FIFO、LRU、LFU等)
四、合理使用SoftReference和WeekReference:
SoftReference的对象会在内存不够用的时候回收,WeekReference的对象会在Full GC的时候回收。
五、资源消耗不多但程序执行慢的情况的解决方法降低锁竞争:
线程多了,锁竞争的状况会比较明显,这时候线程很容易处于等待锁的状况,从而导致性能下降以及CPU sy上升。
六、使用并发包中的类:
大多数采用了lock-free、nonblocking算法。
七、使用Treiber算法:
基于CAS以及AtomicReference。
八、使用Michael-Scott非阻塞队列算法:
基于CAS以及AtomicReference,典型ConcurrentLindkedQueue。(基于CAS和AtomicReference来实现无阻塞是不错的选择,但值得注意的是,lock-free算法需不断的循环比较来保证资源的一致性的,对于冲突较多的应用场景而言,会带来更高的CPU消耗,因此不一定采用CAS实现无阻塞的就一定比采用lock方式的性能好。 还有一些无阻塞算法的改进:MCAS、WSTM等)
九、尽可能少用锁:
尽可能只对需要控制的资源做加锁操作(通常没有必要对整个方法加锁,尽可能让锁最小化,只对互斥及原子操作的地方加锁,加锁时尽可能以保护资源的最小化粒度为单位--如只对需要保护的资源加锁而不是this)。
十、拆分锁:
独占锁拆分为多把锁(读写锁拆分、类似ConcurrentHashMap中默认拆分为16把锁),很多程度上能提高读写的性能,但需要注意在采用拆分锁后,全局性质的操作会变得比较复杂(如ConcurrentHashMap中size操作)。(拆分锁太多也会造成副作用,如CPU消耗明显增加)
十一、去除读写操作的互斥:
在修改时加锁,并复制对象进行修改,修改完毕后切换对象的引用,从而读取时则不加锁。这种称为CopyOnWrite,CopyOnWriteArrayList是典型实现,好处是可以明显提升读的性能,适合读多写少的场景, 但由于写操作每次都要复制一份对象,会消耗更多的内存。
本文介绍了JVM性能优化的关键策略,包括释放不必要的引用、使用对象缓存池、采用合理的缓存失效算法、合理使用软弱引用、降低锁竞争、使用并发包中的类、使用Treiber算法、使用Michael-Scott非阻塞队列算法、尽可能少用锁、拆分锁以及去除读写操作的互斥等。
2755

被折叠的 条评论
为什么被折叠?



