武大oj的题。题目传送门。
以我看,我的代码最大就开两个数组a[1000],b[1000],怎么会用到553728KB的内存。提交了好多次,都是这个数量级的内存消耗。
求大师们拉小弟一把呀:)
Problem id: 1383
Memory: 553728KB Time: 6610ms
Language: Java Result: Memory Limit Exceeded
code:
1 import java.util.*; 2 import java.io.*; 3 4 public class Main 5 { 6 public static final int MAXN = 1000; 7 //public static final String INPUT = "in.txt"; 8 static int max3(int x, int y, int z) 9 { 10 return (x>y?x:y)>z?(x>y?x:y):z; 11 } 12 public static void main(String[] args) 13 { 14 /* 15 try 16 { 17 FileInputStream instream = new FileInputStream(INPUT); 18 System.setIn(instream); 19 } 20 catch(Exception e) 21 { 22 System.err.println("input error!"); 23 } 24 */ 25 int[] a = new int[MAXN]; 26 int[] b = new int[MAXN]; 27 int t,r,c,res; 28 Scanner cin = new Scanner(System.in); 29 t=cin.nextInt(); 30 for(int cas=1; cas<=t; cas++) 31 { 32 r=cin.nextInt(); 33 c=cin.nextInt(); 34 35 //initialize 36 Arrays.fill(a, 0); 37 Arrays.fill(b, 0); 38 39 if(r==1 && c==1) res=cin.nextInt(); 40 else if((r==1 && c>1) || (r>1 && c==1)) 41 { 42 int tmp = (r>c?r:c); 43 for(int i=0; i<tmp; ++i) 44 a[0]+=cin.nextInt(); 45 res=a[0]; 46 } 47 else//r,c>=2 48 { 49 for(int i=0; i<c; ++i) 50 a[i]=cin.nextInt(); 51 for(int i=0; i<c; ++i) 52 b[i]=cin.nextInt(); 53 54 for(int i=1; i<c; ++i) 55 a[i] += a[i-1]; 56 b[0]+=a[0]; 57 58 for(int i=1; i<c; ++i) 59 b[i] += max3(b[i-1], a[i-1], a[i]); 60 61 r -= 2; 62 while(r-- > 0) 63 { 64 for(int i=0; i<c; ++i) 65 a[i]=cin.nextInt(); 66 67 a[0]+=b[0]; 68 for(int i=1; i<c; ++i) 69 a[i] += max3(a[i-1], b[i-1], b[i]); 70 for(int i=1; i<c; ++i) 71 b[i]=a[i]; 72 } 73 res=b[c-1]; 74 } 75 System.out.println("Case #"+cas+": " + res); 76 } 77 } 78 }
貌似也没有哪里有内存泄漏啊……
1. 你申请了两个这么大的数组。
2. cin.nextInt()这个方法内部实现是将System.in的流读到一个CharBuffer里,再转为String,再将这个String转为Integer,最后调用Integer的intValue()方法得到你需要的最终的int类型的数据。
综上所述,你内存占用的的确比较多。
一个int占4字节,int a[1000], int b[1000]两个数组就8KB,怎么会用到500MB?
再者,读入一个int型数据不用cin.nextInt()用什么?它跟C++的cin和C的scanf一样基础,应该不会占很多内存吧……
@duanguyuan:
1. java中的数组与C的不一样,java中的数组在运行时其实是一个对象,所以占用的空间并不是简单的按里面的数字去计算的。
2. cin.nextInt()这个方法你用的是对的,我说的只是这个方法的内部实现决定了会生成较多的临时对象是会占用内存空间的。
3. java跟C、C++在很多地方是不一样的,另外基础的东西并不代表不会速度很快、性价比很高。打个比方:System.out.println()只是一个输出打印的方法,但在大型系统里使用的话会导致系统出现大量的锁等待,降低系统的速度。
@寂灵天: 谢谢指教。我觉得可能是那几个嵌套循环的原因。因为有的题目中我定义int a[50000] 这种数组都没用到500多MB呢,只在几十MB的范围。
@duanguyuan:
你在执行你的代码的时候是依赖于那个INPUT文件的吧,这个文件有多大呢?
Result: Memory Limit Exceeded 这最后是异常了吧,当内存不足时JVM会自动调用GC去清理内存,而这种异常说明你持有的内存太多了,JVM无法释放足够的内存。嵌套循环的确会带来速度上的问题,但跟内存基本没有关系。
本想跑一下看看内存都被什么东东占用了,可以没有你这个INPUT。
@寂灵天: INPUT很简单呀,
Sample Input
你可以在这里看到详细的题目描述http://acm.whu.edu.cn/learn/problem/detail?problem_id=1383
@duanguyuan: 我跑出来没问题呀,你看只用了4.1MB,你的INPUT不是这个吧?
@寂灵天:我用java visual vm查看,确实峰值能够达到500+MB。稳定的时候在20+MB。
谢谢你一直的回复:)
INPUT 就是这个呀。而且,提交到online-judge后,那里的测试数组肯定很多组。但是每组的矩阵行列都不会超过1000.
数数你的代码里有多少static ,再数数你的代码多少for
内存使用完不能及时回收。
谢谢你的答案。但是我还是没名明白。static修饰的变量不是“全局”的、共享内存的么?而且从30行开始的所有 for循环里边的变量,我都是在for外部定义的,每次循环只是更新原有变量的值,又没有创建新变量。
麻烦再点拨一下:)
@duanguyuan: 定义到外部才是极大的降低了垃圾回收,变量那里用那里定义,反正我没见过java里面for循环能写这么多的。
你上面的代码我第一次见这么多的if else, for,while 堆在一起。太可怕了。你可以用eclipse自带的堆栈监视工具看看。
@duanguyuan: static 是放在栈空间里的,而栈空间的东西是可以被任何对象访问的,那就说明他生命周期长喽!他生命周期长说明什么?说明他占用空间的时间也长,比如你程序开始到结束,他一直被占用,所以他用的内存多!
牛B啊,上楼正解+1,嵌套循环内存耗不起啊
不知道cin.nextInt()是什么意思是否有问题,但从代码上是开不出什么问题,楼上不要吾人子弟,FOR编译成代码占内存非常少,
cin.nextInt()就是从输入流中读取下一个int。这里应该没问题。
(刚从C/C++转到java,各种不习惯。最官方的在线java api http://docs.oracle.com/javase/7/docs/api/居然没有搜索的功能,写几行代码好费劲啊)
楼上的,没人说for占内存多呀。是嵌套for里面的代码占得内存多。
我没仔细看LZ代码是干什么的,但是从
for(;;){ for(;;){}..... while(;){ for(;;){ } } }
这种代码结构来看,,占个500M也不奇怪。。。尤其是while里面的,别看才3个循环,其实这样嵌套循环占的内存是几何级递增的。。。
学习!
如果有内存泄露,程序会不断的占用更多的内存,最后会崩溃掉,或者卡死在gc上。
你可以在完成一次循环工作后写一个System.gc(),明确的强制一下gc,观察一下是不是每次回收能收到一个恒定的内存量。从你的代码看只是没有及时回收,是不存在内存泄露的。
用jconsole工具可以强制回收内存,也可以看到内存的占用量。可以用工具看看。
你们说的都对,我再提一点,就是数组为什么要定义那么长,1000个int类型数组,你还定义了两个,电脑真心挺不起!
还有就是for确实太多了!while还有一个