仓酷云 发表于 2015-1-18 11:15:56

JAVA编程:Java中的substring真的会引发内存保守么?仓酷云

其实产生见解的过程就是训练自己发现问题,分析问题的能力。根据以上的认识我想谈下传统的学习与通过视频独立学习的优缺点:在Java中开辟,String是我们开辟程序能够说必需要利用的范例,String有一个substring办法用来截取字符串,我们想必也经常利用。可是你晓得么,关于Java6中的substring是不是会引发内存保守,在外洋的论坛和社区有着一些会商,以致于Java官方已将其标志成bug,而且为此Java7还从头举行了完成。读到这里大概你的成绩就来了,substring怎样会引发内存保守呢?那末我们就带着成绩,走进小黑屋,看看substring有无内存保守,又是怎样招致所谓的内存保守。
基础先容

substring办法供应两种重载,第一种为只承受入手下手截取地位一个参数的办法。

1publicStringsubstring(intbeginIndex)


好比我们利用下面的办法,"unhappy".substring(2)前往了局"happy"
另外一种重载就是承受一个入手下手截取地位和一个停止截取地位的参数的办法。

1publicStringsubstring(intbeginIndex,intendIndex)


利用这个办法,"smiles".substring(1,5)前往了局"mile"
经由过程这个先容我们基础懂得了substring的感化,如许便于我们了解上面的内容。
筹办事情

由于这个成绩呈现的情形在Java6,假如你的Java版本号不是Java6必要调剂一下。
终端调剂(合用于Mac体系)

检察java版本号

123413:03$java-versionjavaversion"1.8.0_25"Java(TM)SERuntimeEnvironment(build1.8.0_25-b17)JavaHotSpot(TM)64-BitServerVM(build25.25-b02,mixedmode)


切换到1.6

1exportJAVA_HOME=$(/usr/libexec/java_home-v1.6)


Ubuntu利用alternatives--configjava,Fedora下面利用alternatives--configjava。
假如你利用Eclipse,能够选择工程,右击,选择Properties(属性)—JavaCompiler(Java编译器)举行特别指定。
成绩重现

这里贴一下java官方bug里用到的重现成绩的代码。

123456789101112131415publicclassTestGC{privateStringlargeString=newString(newbyte);StringgetString(){returnthis.largeString.substring(0,2);}publicstaticvoidmain(String[]args){java.util.ArrayListlist=newjava.util.ArrayList();for(inti=0;i<1000000;i++){TestGCgc=newTestGC();list.add(gc.getString());}}}


但是下面的代码,只需利用Java6(Java7和8都不会抛出非常)运转一下就会报java.lang.OutOfMemoryError:Javaheapspace的非常,这申明没有充足的堆内存供我们创立对象,JVM选择了抛出非常操纵。
因而有人会说,是由于你每一个轮回中创立了一个TestGC对象,固然我们到场ArrayList只是两个字符的字符串,可是这个对象中又存储largeString这么年夜的对象,如许一定会形成OOM的。
但是,实在你说的不合错误。好比我们看一下如许的代码,我们只修正getString办法。

publicStringsubstring(intbeginIndex)0publicStringsubstring(intbeginIndex)1


实行下面的办法,其实不会招致OOM非常,由于我们持有的时1000000个ab字符串对象,而TestGC对象(包含个中的largeString)会在java的渣滓接纳中开释失落。以是这里不会存在内存溢出。
那末事实是甚么招致的内存保守呢?要研讨这个成绩,我们必要看一下办法的完成,便可。
深切Java6完成

在String类中存在如许三个属性


[*]value字符数组,存储字符串实践的内容
[*]offset该字符串在字符数组value中的肇端地位
[*]count字符串包括的字符的长度
Java6中substring的完成

publicStringsubstring(intbeginIndex)2publicStringsubstring(intbeginIndex)3


上述办法挪用的机关办法

publicStringsubstring(intbeginIndex)4publicStringsubstring(intbeginIndex)5


当我们读完上述的代码,我们应当会名顿开,本来是这个模样啊!
当我们挪用字符串a的substring失掉字符串b,实在这个操纵,不过就是调剂了一下b的offset和count,用到的内容仍是a之前的value字符数组,并没有从头创立新的专属于b的内容字符数组。
举个和下面重古代码相干的例子,好比我们有一个1G的字符串a,我们利用substring(0,2)失掉了一个只要两个字符的字符串b,假如b的性命周期要善于a大概手动设置a为null,当渣滓接纳举行后,a被接纳失落,b没有接纳失落,那末这1G的内存占用仍旧存在,由于b持有这1G巨细的字符数组的援用。
看到这里,人人应当能够分明下面的代码为何呈现内存溢出了。
共享内容字符数组

实在substring中天生的字符串与原字符串共享内容数组是一个很棒的计划,如许制止了每次举行substring从头举行字符数组复制。正如其文档申明的,共享内容字符数组为了就是速率。可是关于本例中的成绩,共享内容字符数组显得有点糟糕。
怎样办理

关于之前对照不罕见的1G字符串只截取2个字符的情形可使用上面的代码,如许的话,就不会持有1G字符串的内容数组援用了。

1publicStringsubstring(intbeginIndex)7


上面的这个机关办法,在源字符串内容数组长度年夜于字符串长度时,举行数组复制,新的字符串会创立一个只包括源字符串内容的字符数组。

publicStringsubstring(intbeginIndex)8publicStringsubstring(intbeginIndex)9


Java7完成

在Java7中substring的完成丢弃了之前的内容字符数组共享的机制,关于子字符串(本身除外)接纳了数组复制完成单个字符串持有本人的应当具有的内容。

1011


substring办法中挪用的机关办法,举行内容字符数组复制。

publicStringsubstring(intbeginIndex)213


真的是内存保守么

我们晓得了substring某些情形下大概引发内存成绩,可是这个叫做内存保守么?
实在团体以为这个不该该算为内存保守,利用substring天生的字符串b当然会持有原有字符串a的内容数组援用,可是当a和b都被接纳以后,该字符数组的内容也是能够被渣滓接纳失落的。
哪一个版本完成的好

关于Java7对substring做的修正,收到了批驳纷歧的反应。
团体加倍偏向于Java6的完成,当举行substring时,利用共享内容字符数组,速率会更快,不必从头请求内存。固然有大概呈现本文中的内存功能成绩,但也是无方法能够办理的。
Java7的完成不必要程序员特别操纵制止了本文中成绩,可是举行每次substring的操纵功能总会比java6的完成要差一些。这类完成显得有点“糟”。
成绩的代价

固然这个成绩呈现在Java6而且Java7中已修复,但其实不代表我们就不必要懂得,何况Java7的从头完成被喷的很凶猛。
实在这个成绩的代价,仍是对照可贵的,特别是内容字符数组共享这个优化的完成。但愿能够为人人今后的计划完成供应匡助和一些设法。
受影响的办法

trim和subSequence都存在挪用substring的操纵。Java6和Java7substring完成的变动也直接影响到了这些办法。
参考资本

以下三篇文章写得都对照不错,可是都略微有一些成绩,我都已标明出来,人人浏览时,必要注重。

先说优点,首先和C,C++这些语言比起来,java很简单,去掉指针的java,非常好理解,自动垃圾回收机制也很好,自从JDK1.5推出以后,性能上又有了很大提高。

小魔女 发表于 2015-1-20 18:50:14

当然你也可以参加一些开源项目,一方面可以提高自己,另一方面也是为中国软件事业做贡献嘛!开发者在互联网上用CVS合作开发,用QQ,MSN,E-mail讨论联系,天南海北的程序员分散在各地却同时开发同一个软件,是不是很有意思呢?

简单生活 发表于 2015-1-22 07:14:32

如果要向java web方向发展也要吧看看《Java web从入门到精通》学完再到《Struts2.0入门到精通》这样你差不多就把代码给学完了。有兴趣可以看一些设计模块和框架的包等等。

兰色精灵 发表于 2015-1-25 12:30:27

Java 不同于一般的编译执行计算机语言和解释执行计算机语言。它首先将源代码编译成二进制字节码(bytecode),然后依赖各种不同平台上的虚拟机来解释执行字节码。从而实现了“一次编译、到处执行”的跨平台特性。

再见西城 发表于 2015-1-29 12:12:22

Java自面世后就非常流行,发展迅速,对C++语言形成了有力冲击。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控制台

爱飞 发表于 2015-2-4 07:12:52

如果你学过HTML,那么事情要好办的多,如果没有,那你快去补一补HTML基础吧。其实JSP中的Java语法也不多,它更象一个脚本语言,有点象ASP。

飘飘悠悠 发表于 2015-2-9 18:35:19

Java语言支持Internet应用的开发,在基本的Java应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、ServerSocket等。Java的RMI(远程方法激活)机制也是开发分布式应用的重要手段。

分手快乐 发表于 2015-2-27 16:26:17

是一种突破用户端机器环境和CPU

若相依 发表于 2015-3-4 22:17:16

不过,每次的执行编译后的字节码需要消耗一定的时间,这同时也在一定程度上降低了 Java 程序的运行效率。

第二个灵魂 发表于 2015-3-9 18:54:53

还好,SUN提供了Javabean可以把你的JSP中的 Java代码封装起来,便于调用也便于重用。

乐观 发表于 2015-3-13 01:07:10

Sun公司看见Oak在互联网上应用的前景,于是改造了Oak,于1995年5月以Java的名称正式发布。Java伴随着互联网的迅猛发展而发展,逐渐成为重要的网络编程语言。
页: [1]
查看完整版本: JAVA编程:Java中的substring真的会引发内存保守么?仓酷云