看JTS源码,感受Java优化编程(一)
2007年以来,从Geotools、PostGIS到JTS Topology Suite再到java优化编程感受,看似过程相当的复杂,而且相当的凌乱。呵呵,都是Geotools惹的祸呀,没有办法,为了能深度使用Geotools我只能研究JTS Topology Suite,在学习JTS过程中又有一些感想,呵呵,其实从目的而言跨度没有那么大,只是一个磨刀不误砍柴功的过程。
读了一些JTS的源码,呵呵,不对不是一些,而只是com.vividsolutions.jts.geom中的一部分那,还不到整个JTS Topology Suite源码的1/10的代码,对其实现思路可能还不是很清晰,但是看着大拿们写的代码还是让我觉得很有收获。这些收获有我以前没有感受的,也有以前知道原理但是就是不去重视的内容。写在这些文字当作是对自己编程风格的一篇械文。也希望在学习JTS的过程中能从大拿们的代码中学习到更多的内容,最终使得自己不仅仅学习这些编程大拿成果的使用,更使自己能提高自己的代码质量。
作为自己对Java优化编程感受的开篇,还是从最基础的GC开始吧。呵呵,毕竟GC的存在是Java的特色之一,但是如果完全依托于JVM中的GC就想获取良好的程序效率太困难了,这一点相信很多人都有一个清楚的认识。如何合理的使用Java回收机制,如何让GC更快的实施回收,我想也许很多程序员和我一样都不是很重视,所以先来抛个砖,让朋友们一起来批判一下。
(一下文字中有一些引用了曾经看过的《JVM初探》、《Java的GC机制》等牛人文章,由于时间太长,很多定义我无法记住来源,所以就不一一标明了。望原作者谅解!ps:标题貌似是这个)
Java程序中的内存管理机制是通过GC完成的,“一个对象创建后被放置在JVM的堆内存中,当永远不在应用这个对象的时候将会被JVM在堆内存中回收。被创建的对象不能再生,同时也没有办法通过程序语句释放”(这个是《Java的GC机制》中提到的定义,呵呵,还依稀记得)这就是GC对垃圾对象的定义。个人感觉这么解释或许会比较快理解:在运行环境中JVM会对两种内存进行管理,一种是堆内存(对象实例或者变量),一种是栈内存(静态或非静态方法),而JVM所管理的内存区域实际上就是堆内存+栈内存(MS:对象实例+实例化变量+静态方法+非静态方法),当JVM在其所管理的内存区域的中无法通过根集合到达对象的时候就会将此对象作为垃圾对象实施回收。
Java所有的对象都有一个生命周期:创建、使用、不可视、不可到达、回收释放。先就从这个过程中结合昨天(2月9日)10点到今天(2月10日)凌晨2点看JTS代码的一些感受,对自己来个自我批评吧,同时也对自己的一些经验做一次总结(呵呵,在老爸家,无法上网,都不知道什么时候可以帖到Blog去)
- 创建阶段
先来看看我从JTS代码中感受到我需要立刻改正的错误,虽说理论上我明白道理,但是我就是没有去做过,也许这就是易做图和易做图兄的区别吧。。。汗自己一个。。。
我的代码中曾经出现过这样的代码:
List alist=uSvr.getUserinfoList();
for(int i=0;i<alist.size();i++){
//首先这里就有问题,这个是Crespo小兄弟给我提出的。最好使用for(int i=0 p=alist.size();i<p;i++),避免alist由于在循环体中发生变化时所带来的问题,而且即便alist没有发生变化,这么做也避免程序不断去执行size()方法所带来的资源损耗。赞一个先,因为Crespo所提到的思路在JTS代码中易做图们都这么干,而且也绝对应该这么干
Object obj=new Object();
//这里问题大了。创建对象第一忌:不要在循环体中创建对象。这种做易做图在内存中保存N份这个对象的引用//会浪费大量的内存空间(虽说内存便宜,可以进行硬件升级),同时JVM的GC机制会因为这些无谓的对象做大量//的回收工作,系统不慢都不行呀。。。好在这个问题很早以前就被我注意了,现在我的做法时在循环体外首先声明一个空对象,然后在循环体内new一个出来。
。。。。。。
}
现在我写的代码中出现这种情况
public class Test{
Object obj=new Object();
public Test(){
obj=new Object();
//我的代码将Object对象初始化了两次。这个给内存带去的消耗绝对不比在循环体中创建对象来得小。创建对象第二忌:尽可能不要多次初始化对象。我这个问题也是恰好这两天在给一个公司做一个SP数据转发的开发中写过的。看JTS的易做图们的代码在想流程的时候,偶然发现这个问题,但是那个汗呀。。真的。。汗流成河。。。
}
}
除了上面两大忌讳外,对象在创建过程中还需要注意到以下问题。不采用过深的集成关系;访问本地变量由于访问类变量。这两点很多书都有提到。
- 使用阶段
其实对象在使用阶段的优化,JTS的源码给我了一种提示,那就是java.lang.ref的有效利用。这个包实际上我今天是第一次看,从来都没有注意过这个包的使用问题,虽说它属于java.lang核心开发API中的范畴。知道看到JTS源码中出现这个代码我才“带着这玩意干什么的?”的疑问翻了一下API。
结合JTS源码中的写法以及所查阅的API的内容,说说我的感受吧。首先在java.lang.ref包中最值得我们多关注的是如何合理的使用SoftReference以及WeakReference。也就是我么那如何将我们的对象置为软引用和弱引用。在API上有软引用以及弱引用的详细解析,俺就不JY了,哪些人更不得了,都是火星派来介绍地球什么叫Java的外星人。很是先看看JTS代码中易做图们的程序风格吧:
Object obj = new Object();
使用obj对象过程
SoftReference softReference = new SoftReference(obj); // 将obj设置为软引用类型
obj = null ; // 强制释放引用
// obj对象再次使用时应该做的处理
if (softReference != null ) {
obj = softReference.get();
} else {
obj = new Object();