实践中的重构27_不要忘了内存空间

方法在设计中,一般关注的是方法的功能契约,即方法需要什么样的参数,方法运行时会保持什么样的不变量,方法运行后会得到什么样的输出。较少会关注到方法的非功能性特征,典型的为方法的执行时间,方法执行时的内存空间消耗等等。
最近关注到一段代码,因为该段代码是导致OutOfMemoryError的一个因素,所以拿来一看。
	public enum WorkingDay {

Monday("星期一"), Tuesday("星期二"), Wednesday("星期三"), Thursday("星期四"), Friday(
"星期五");

private String des;

public static WorkingDay findWorkingDayByDes(String des) {
return getDesWorkingDayMap().get(des);
}

private static Map<String, WorkingDay> getDesWorkingDayMap() {
Map<String, WorkingDay> map = new HashMap<String, WorkingDay>();
for (int i = 0; i < WorkingDay.values().length; i++) {
map.put(WorkingDay.values()[i].des, WorkingDay.values()[i]);
}
return map;
}

private WorkingDay(String des) {
this.des = des;
}
}

注意,原有问题的枚举定义中的枚举值个数较多,这里使用只包含5个枚举值的WorkingDay来说明问题。
该代码提供一个功能,使用des查找对应的WorkingDay枚举。因为每次查找的时候都会新建一个map,在并发较多的时候,新建了大量重复的对象,给jvm内存管理带来了不必要的压力,最后和其他因素共同导致OutOfMemoryError。
想到的修复方法很直接。
		public static WorkingDay findWorkingDayByDes_1(String des) {
for (WorkingDay workingDay : WorkingDay.values()) {
if (workingDay.des.equals(des)) {
return workingDay;
}
}
return null;
}

咋看没有问题,但是这个实现还是有可能多分配空间的,因为不清楚values返回的数组是不是同一个,还是写个test比较保险。
	@Test
public void test() {
WorkingDay[] t1 = WorkingDay.values();
WorkingDay[] t2 = WorkingDay.values();

Assert.assertNotSame(t1, t2);

Assert.assertEquals(t1.length, t2.length);

for (int i = 0; i < t1.length; i++) {
Assert.assertSame(t1[i], t2[i]);
}
}

恩,确定了,返回的数组不是同一个,虽然里面的元素是相同的。也就是说,还是存在一些内存的重复浪费。
Cache是计算机的编程利器啊。看来要控制内存分配较少的空间还是用cache比较靠谱。
		public static Map<String, WorkingDay> cache;

static {
cache = new HashMap<String, WorkingDay>();
for (int i = 0; i < WorkingDay.values().length; i++) {
cache.put(WorkingDay.values()[i].des, WorkingDay.values()[i]);
}
}

public static WorkingDay findWorkingDayByDes_2(String des) {
return cache.get(des);
}

如此一来,整个程序运行期间所消耗的内存基本是确定的,不会随着压力的增大消耗太多的内存空间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值