锁定老帖子 主题:实践中的重构27_不要忘了内存空间
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-06-06
最近关注到一段代码,因为该段代码导致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; } } 该代码提供一个功能,使用des查找对应的WorkingDay枚举。因为每次查找的时候都会新建一个map,因此导致了新建了大量对象,GC来不及回收,最后导致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]); } } 恩,确定了,返回的数组不是同一个,虽然里面的元素是相同的。也就是说,在大压力下,还是会OutOfMemoryError。 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); } 如此一来,整个程序运行期间所消耗的内存基本是确定的,不会随着压力的增大消耗太多的内存空间。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-06-07
GC来不及回收,这就很神奇。。。。。。。
|
|
返回顶楼 | |
发表时间:2011-06-07
这个很明显应该把map做成static
|
|
返回顶楼 | |
发表时间:2011-06-08
这个问题都可以拿来做主题?
|
|
返回顶楼 | |
发表时间:2011-06-08
请教为什么GC会来不及回收呢?
map每次调用以后没有就没有任何变量引用map了 map最后都必然会被回收掉吧 当然效率会有点差 |
|
返回顶楼 | |
发表时间:2011-06-08
humaeks 写道 GC来不及回收,这就很神奇。。。。。。。
很正常的事情。 其实,越是平常的事情,做好了并不容易。 楼主期待下一个 |
|
返回顶楼 | |
发表时间:2011-06-08
恩,很不错,这个static是必须的,随随便便写代码不行
|
|
返回顶楼 | |
发表时间:2011-06-08
最后修改:2011-06-08
我很想请教下是怎么来不及回收。为了免的信口开河,我写了个简单测试,调用这个方法一亿次,观察gc情况。代码: /** * @param args */ public static void main(String[] args) { long result = 0; for (int i = 0; i < 100000000; i++) result += WorkingDay.findWorkingDayByDes("星期一").ordinal(); System.out.println(result); }
jstat观察到的gc状况: S0 S1 E O P YGC YGCT FGC FGCT GCT 25.00 0.00 0.00 0.36 12.75 2464 0.467 0 0.000 0.467 25.00 0.00 0.00 0.36 12.75 2582 0.488 0 0.000 0.488 0.00 25.00 0.00 0.36 12.75 2707 0.510 0 0.000 0.510 0.00 25.00 0.00 0.36 12.75 2787 0.528 0 0.000 0.528 0.00 25.00 72.48 0.36 12.75 2866 0.550 0 0.000 0.550 25.00 0.00 18.12 0.36 12.75 2918 0.560 0 0.000 0.560 没有一次full gc,平均一次minor gc在1.8毫秒。 |
|
返回顶楼 | |
发表时间:2011-06-08
dennis_zane 写道 我很想请教下是怎么来不及回收。为了免的信口开河,我写了个简单测试,调用这个方法一亿次,观察gc情况。代码: /** * @param args */ public static void main(String[] args) { long result = 0; for (int i = 0; i < 100000000; i++) result += WorkingDay.findWorkingDayByDes("星期一").ordinal(); System.out.println(result); }
jstat观察到的gc状况: S0 S1 E O P YGC YGCT FGC FGCT GCT 25.00 0.00 0.00 0.36 12.75 2464 0.467 0 0.000 0.467 25.00 0.00 0.00 0.36 12.75 2582 0.488 0 0.000 0.488 0.00 25.00 0.00 0.36 12.75 2707 0.510 0 0.000 0.510 0.00 25.00 0.00 0.36 12.75 2787 0.528 0 0.000 0.528 0.00 25.00 72.48 0.36 12.75 2866 0.550 0 0.000 0.550 25.00 0.00 18.12 0.36 12.75 2918 0.560 0 0.000 0.560 没有一次full gc,平均一次minor gc在1.8毫秒。 JDK版本,那个公司的jvm |
|
返回顶楼 | |
发表时间:2011-06-09
最后修改:2011-06-09
坏孩子 写道
dennis_zane 写道
我很想请教下是怎么来不及回收。为了免的信口开河,我写了个简单测试,调用这个方法一亿次,观察gc情况。代码: /** * @param args */ public static void main(String[] args) { long result = 0; for (int i = 0; i < 100000000; i++) result += WorkingDay.findWorkingDayByDes("星期一").ordinal(); System.out.println(result); }
jstat观察到的gc状况: S0 S1 E O P YGC YGCT FGC FGCT GCT 25.00 0.00 0.00 0.36 12.75 2464 0.467 0 0.000 0.467 25.00 0.00 0.00 0.36 12.75 2582 0.488 0 0.000 0.488 0.00 25.00 0.00 0.36 12.75 2707 0.510 0 0.000 0.510 0.00 25.00 0.00 0.36 12.75 2787 0.528 0 0.000 0.528 0.00 25.00 72.48 0.36 12.75 2866 0.550 0 0.000 0.550 25.00 0.00 18.12 0.36 12.75 2918 0.560 0 0.000 0.560 没有一次full gc,平均一次minor gc在1.8毫秒。 JDK版本,那个公司的jvm
dennis@dennis-laptop:~$ /opt/jdk1.6.0_18/bin/java -version |
|
返回顶楼 | |