最近在做性能分析,使用ECLIPSE的TPTP做性能分析,虽然早前知道频繁的调用方法是比较耗性能的,毕竟需要维持一个调用栈,具体的理论已经模糊了,就拿实践来叙述一个问题吧。
有如下代码
/**
* get cache define list
*
* @return List<Wt_cacheDomain>
*/
public Map<String, Wt_cacheDomain> getCacheCfgMap() {
if (cacheCfgMap == null) {
cacheCfgMap = new HashMap<String, Wt_cacheDomain>();
// DEBUG
if (getWt_cacheList() != null && !getWt_cacheList().isEmpty()) {
for (int i = 0; i < getWt_cacheList().size(); i++) {
Wt_cacheDomain cacheDomain = (Wt_cacheDomain) getWt_cacheList()
.get(i);
cacheCfgMap.put(cacheDomain.getCache_name(), cacheDomain);
}
}
}
return cacheCfgMap;
}
// 这里要从缓存取,不能实施从数据库加载
public Wt_cacheDomain getCacheWithName(String cacheName) {
// Map<String, Wt_cacheDomain> cacheConfigMap = getCacheCfgMap();
if (cacheName == null || "".equals(cacheName)
|| getCacheCfgMap() == null
|| getCacheCfgMap().isEmpty()) {
return null;
} else {
return getCacheCfgMap().get(cacheName);
}
}
从上述的代码分析,在getCacheWithName()中我使用了三次的getCacheCfgMap(),这样在一个300次有对getCacheWithName()进行操作的程序中通过TPTP分析如下:
可以看到getCacheCfgMap()的平均执行性能为0.0001116秒
因此我修改代码后如下:
public Map<String, Wt_cacheDomain> getCacheCfgMap() {
if (cacheCfgMap == null) {
cacheCfgMap = new HashMap<String, Wt_cacheDomain>();
if (getWt_cacheList() != null && !getWt_cacheList().isEmpty()) {
for (int i = 0; i < getWt_cacheList().size(); i++) {
Wt_cacheDomain cacheDomain = (Wt_cacheDomain) getWt_cacheList()
.get(i);
cacheCfgMap.put(cacheDomain.getCache_name(), cacheDomain);
}
}
}
return cacheCfgMap;
}
public Wt_cacheDomain getCacheWithName(String cacheName) {
//注意我这里用一个变量保存getCacheCfgMap()的值,这样这个方法就只有一次的调用.
Map<String, Wt_cacheDomain> cacheConfigMap = getCacheCfgMap();
if (cacheName == null || "".equals(cacheName)
|| cacheConfigMap == null
|| cacheConfigMap.isEmpty()) {
return null;
} else {
return cacheConfigMap.get(cacheName);
}
}
注意注释的部分,这样getCacheWithName()就只调用了一次cacheConfigMap(),同样环境执行通过TPTP的分析如下:
不但Calls减少到了301次,而且平均执行时间也减少到0.000007次。
那么再继续修改代码如下为:
public Map<String, Wt_cacheDomain> getCacheCfgMap() {
if (cacheCfgMap == null) {
cacheCfgMap = new HashMap<String, Wt_cacheDomain>();
if (getWt_cacheList() != null && !getWt_cacheList().isEmpty()) {
for (int i = 0; i < getWt_cacheList().size(); i++) {
Wt_cacheDomain cacheDomain = (Wt_cacheDomain) getWt_cacheList()
.get(i);
cacheCfgMap.put(cacheDomain.getCache_name(), cacheDomain);
}
}
}
return cacheCfgMap;
}
public Wt_cacheDomain getCacheWithName(String cacheName) {
//注意我这里用一个变量保存getCacheCfgMap()的值,这样这个方法就只有一次的调用.
Map<String, Wt_cacheDomain> cacheConfigMap = getCacheCfgMap();
cacheConfigMap = getCacheCfgMap();
cacheConfigMap = getCacheCfgMap();
cacheConfigMap = getCacheCfgMap();
cacheConfigMap = getCacheCfgMap();
cacheConfigMap = getCacheCfgMap();
cacheConfigMap = getCacheCfgMap();
if (cacheName == null || "".equals(cacheName)
|| cacheConfigMap == null
|| cacheConfigMap.isEmpty()) {
return null;
} else {
return cacheConfigMap.get(cacheName);
}
}
cacheConfigMap = getCacheCfgMap();这里故意多调用了六次,那么是否性能会第一段代码还差呢?继续看TPTP结果
被调用了2107次,但是平均时间比第一段代码要好很多,说明对于无用的重复代码,java进行了必要的优化处理,但是仍旧比第二段代码性能差。
总结:
1.如果一个方法多次调用其他方法并且其作用都是一样,获取值也同样的情况下,使用临时变量来保存调用后的值,在压力下不但因减少了调用次数而提高性能,还能提高被调用方法的性能。
2.一个方法本身被调用的压力越大,它执行性能会越差,是否存在零界点,还未知。