邂逅StringIndexOutOfBoundsException

今天在WCS的测试中邂逅了这个从未接触的exception

迫使我对它做了一些分析


首先:
“不断的将被选中的字符串加到某一字符串末尾,当长度超过一定量时提示:
java.lang.StringIndexOutOfBoundsException:Stringindexoutofrange:10
”并不能说明String有长度限制

JavaAPI指出StringIndexOutOfBoundsException异常
ThrownbyStringmethodstoindicatethatanindexiseithernegativeorgreaterthanthesizeofthestring.ForsomemethodssuchasthecharAtmethod。
上面的错误是因为
String.length()<10;
而你又要取index>=10的字符从而抛出上面异常
String其实是没有限制的,而是当String太大了,超过JVM的自身的内存后会抛出
java.lang.OutOfMemoryError错误

String是没有长度限制的,而是有JVM的内存限制了String的长度

在dayworker的blog中还提到

quote:


publicclasstestString{
publicstaticvoidmain(Stringargs[])
{
Strings="abbbbb";
System.out.println("JVMMAXMEMORY:"+Runtime.getRuntime().maxMemory()/1024/1024+"M");
System.out.println("JVMISUSINGMEMORY:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
Runtime.getRuntime().traceMethodCalls(true);
while(true)
{
try{
s=s+s;

}catch(Exceptione)
{
System.out.println(e);
}
catch(Erroro)
{Stringunit=null;
intsizeb=s.length();
intsize=sizeb;
inttime=0;
while(size>1024)
{
size=size/1024;
time++;
}
switch(time)
{
case0:unit="byte";break;
case1:unit="k";break;
case2:unit="M";break;
default:unit="byte";
}

System.out.println("Stringhasusedmemory:"+size+unit);
System.out.println("JVMISUSINGMEMORY:"+(float)Runtime.getRuntime().totalMemory()/1024/1024+"M");
System.out.println("MemoryError:"+o);
break;
}

}
}
}
然后我们用JVM的默认参数执行(我的机器内存是128M)
javatestString
结果:
JVMMAXMEMORY:128M
JVMISUSINGMEMORY:1M
Stringhasusedmemory:12M
JVMISUSINGMEMORY:63.5625M
MemoryError:java.lang.OutOfMemoryError
开始JVM使用的内存是1M,当String为12M,JVM使用了63M多时
JVM溢出。

然后,我们用限制JVM内存大小的参数来执行,限制最大内存5M
java-mx5mtestString
结果:
JVMMAXMEMORY:70M
JVMISUSINGMEMORY:1M
Stringhasusedmemory:768.0k
JVMISUSINGMEMORY: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用chararray实现,就肯定由长度限制的,不能用memory来衡量

==================================
例如上面的程序改用StringBuffer实现,就可以得到极大的改善。
下面是我改用StringBuffer做的测试:
注意:程序循环了2097150次!
是使用String的程序的99864倍!

publicclassTestStringBuffer{
publicstaticvoidmain(Stringargs[])
{
Strings="abbbbb";
StringBuffersb=newStringBuffer(s);
System.out.println("JVMISUSINGMEMORY:"+
(Runtime.getRuntime().totalMemory()/1024/1024)+
"M");
Runtime.getRuntime().traceMethodCalls(true);

intcount=0;
while(true)
{
try{
sb.append(s);
count++;

}catch(Exceptione)
{
System.out.println(e);
}
catch(Erroro)
{
Stringunit=null;
intsize=sb.length();
size*=2;

inttime=0;
while(size>1024)
{
size=size/1024;
time++;
}
switch(time)
{
case0:unit="byte";break;
case1:unit="k";break;
case2:unit="M";break;
default:unit="byte";
}

System.out.println("Looptimes:"+count);
System.out.println("Stringhasusedmemory:"+size+unit);
System.out.println("JVMISUSINGMEMORY:"+
(float)Runtime.getRuntime().totalMemory()/1024/1024+
"M");
System.out.println("MemoryError:"+o);
break;
}

}
}
}

输出结果:
JVMISUSINGMEMORY:1M
Looptimes:2097150
Stringhasusedmemory:23M
JVMISUSINGMEMORY:63.75M
MemoryError:java.lang.OutOfMemoryError



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





以上来自dayworker的blog,感谢他的总结,希望可以与dayworker成为朋友
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值