已经解决java.lang.OutOfMemoryError

03-07-11 cute
有人说:

“不断的将被选中的字符串加到某一字符串末尾,当长度超过一定量是就提示:

java.lang.StringIndexOutOfBoundsException: String index out of range: 10

”说明String有长度限制。

看一下Java API就会知道

java.lang.StringIndexOutOfBoundsException出现的情况是

Thrown by String methods to indicate that an index is either negative or greater than the size of the string. For some methods such as the charAt method。

上面的错误是因为

String.length()<10;

而你又要取index>=10的字符,自然就会抛出上面的例外。

String其实是没有限制的,而是当String太大了,超过JVM的自身的内存后会抛出

java.lang.OutOfMemoryError错误

下面作个实验:

public class testString{

public static void main(String args[])

{

String s="abbbbb";

System.out.println("JVM MAX MEMORY: "+Runtime.getRuntime().maxMemory()/1024/1024+"M");

System.out.println("JVM IS USING MEMORY:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");

Runtime.getRuntime().traceMethodCalls(true);

while(true)

{

try{

s=s+s;

}catch(Exception e)

{

System.out.println(e);

}

catch(Error o)

{ String unit = null;

int sizeb = s.length();

int size = sizeb;

int time = 0;

while(size>1024)

{

size = size/1024;

time++;

}

switch(time)

{

case 0: unit = "byte";break;

case 1: unit = "k"; break;

case 2: unit = "M"; break;

default : unit = "byte";

}

System.out.println("String has used memory:"+size+unit);

System.out.println("JVM IS USING MEMORY:"+(float)Runtime.getRuntime().totalMemory()/1024/1024+"M");

System.out.println("MemoryError:"+o);

break;

}

}

}

}

然后我们用JVM的默认参数执行(我的机器内存是128M)

java testString

结果:

JVM MAX MEMORY: 128M

JVM IS USING MEMORY:1M

String has used memory:12M

JVM IS USING MEMORY:63.5625M

MemoryError:java.lang.OutOfMemoryError

开始JVM使用的内存是1M,当String为12M,JVM使用了63M多时

JVM溢出。

然后,我们用限制JVM内存大小的参数来执行,限制最大内存5M

java -mx5m testString

结果:

JVM MAX MEMORY: 70M

JVM IS USING MEMORY:1M

String has used memory:768.0k

JVM IS USING MEMORY:5.9375M

MemoryError:java.lang.OutOfMemoryError

开始JVM使用的内存是1M,当String为768k,JVM使用了5M多时

JVM溢出。

大家还可以改变 -mx参数,来进一步做实验。

以上两个实验证明,String是没有长度限制的,而是有JVM的内存限制了String的长度。同时说明,并不会抛出任何Exception而只会抛出Error.

OutMemoryError表明程序的设计很差,或者遇到了超出编程人员所预想的大批量的数据。不管哪种情况,都只有下面这几种解决办法。它们是:

设计人员重新设计程序,不致使程序一次载入所有的数据。

数据可以分割成更小的块。

可以为程序分配更多的内存。

为Java虚拟机提供更多的内存。

而上面的例子是为虚拟机提供更多的内存

=======================================

其实应该少用String这东西,特别是 String的 +=操作

不仅原来的String对象不能继续使用,主要是又要new出N多的新对象出来,再多的memory也要out~~

String用char array实现,就肯定由长度限制的,不能用memory来衡量

==================================

例如上面的程序改用StringBuffer实现,就可以得到极大的改善。

下面是我改用StringBuffer做的测试:

注意:程序循环了2097150次!

是使用String的程序的99864倍!

public class TestStringBuffer{

public static void main(String args[])

{

String s="abbbbb";

StringBuffer sb = new StringBuffer(s);

System.out.println("JVM IS USING MEMORY:"+

(Runtime.getRuntime().totalMemory()/1024/1024)+

"M");

Runtime.getRuntime().traceMethodCalls(true);

int count = 0;

while(true)

{

try{

sb.append(s);

count++;

}catch(Exception e)

{

System.out.println(e);

}

catch(Error o)

{

String unit = null;

int size = sb.length();

size *= 2;

int time = 0;

while(size>1024)

{

size = size/1024;

time++;

}

switch(time)

{

case 0: unit = "byte";break;

case 1: unit = "k"; break;

case 2: unit = "M"; break;

default : unit = "byte";

}

System.out.println("Loop times:"+count);

System.out.println("String has used memory:"+size+unit);

System.out.println("JVM IS USING MEMORY:"+

(float)Runtime.getRuntime().totalMemory()/1024/1024+

"M");

System.out.println("MemoryError:"+o);

break;

}

}

}

}

输出结果:

JVM IS USING MEMORY:1M

Loop times:2097150

String has used memory:23M

JVM IS USING MEMORY:63.75M

MemoryError:java.lang.OutOfMemoryError

=====================

从另一方面说,如果你要处理的字符串达到百兆甚至上GB,使用String对象,根本没法工作,所以这个问题不需要太多讨论。看一下jdk的源文件,String的长度是String对象的一个成员count,类型是int,不是long,也不是char。知道这些,我认为够了。

1
cute
2003-07-11 16:57
我相信。这个问题大家都遇到过。内存溢出,已经郁闷了 我好长时间。

今天看这篇文章,也就明白我得项目为什么总是有:

java.lang.OutOfMemoryError

cute
2003-07-11 17:17

为什么 加入参数后执行速度更慢?

java -mx256m testString

=======================

C:\>java testString

JVM IS USING MEMORY:1M

Loop times:2097150

String has used memory:23M

JVM IS USING MEMORY:63.5625M

MemoryError:java.lang.OutOfMemoryError

C:\>java -mx256m testString

JVM IS USING MEMORY:1M

Loop times:8388606

String has used memory:95M

JVM IS USING MEMORY:254.0625M

MemoryError:java.lang.OutOfMemoryError

iceant
2003-07-11 21:39
从哪里看是慢了?

times? times 指的是循环次数,而不是时间,时间是不可数的

laoduwu
2003-10-10 17:33
我试验了这段代码,我发现其实用string和stringbuffer是差不多的。

楼主的例子是不能说明问题的,因为

用string的时候:

s=s+s;

而用StringBuffer的时候是

sb.append(s);

前一个是指数级往上涨,而后一个是每次只加一小段,这完全不能这样来比较啊

而我都是每次只加一小段的测试的话,好像用String还要好一些似的。

看到很多在说用StringBuffer好,到底如何来证明?

oldma
2003-10-15 08:46

内存中的对象大致可以分为两种,需要回收的对象和不需要回收的对象

如果程序的应用很多对象应用一次就成为垃圾的话,java的内存变大了,

java做垃圾回收的间隔时间也就变长,做一次垃圾回收的时间变长。虚拟机在作垃圾回收时,系统是很慢的。

所以单存加大内存不能改变应用的performance,改变内存的目的应该是让垃圾回收的间隔时间不要太短同时一次垃圾回收的时间不要太长,具体的时间参数可以通过-verbosegc > XXX.txt 打印到文件里来观察。

guohelp
2005-08-29 12:23
System.out.println("JVM IS USING MEMORY:"+Runtime.getRuntime().totalMemory

和gc的内存情况对不上呀?

为什么呢

猜你喜欢