日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java中由substring方法引发的内存泄漏

發(fā)布時(shí)間:2024/4/11 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中由substring方法引发的内存泄漏 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。

?

在Java中我們無須關(guān)心內(nèi)存的釋放,JVM提供了內(nèi)存管理機(jī)制,有垃圾回收器幫助回收不需要的對(duì)象。但實(shí)際中一些不當(dāng)?shù)氖褂萌匀粫?huì)導(dǎo)致一系列的內(nèi)存問題,常見的就是內(nèi)存泄漏和內(nèi)存溢出

內(nèi)存溢出(out of memory )?:通俗的說就是內(nèi)存不夠用了,比如在一個(gè)無限循環(huán)中不斷創(chuàng)建一個(gè)大的對(duì)象,很快就會(huì)引發(fā)內(nèi)存溢出。

內(nèi)存泄漏(leak of memory)?:是指為一個(gè)對(duì)象分配內(nèi)存之后,在對(duì)象已經(jīng)不在使用時(shí)未及時(shí)的釋放,導(dǎo)致一直占據(jù)內(nèi)存單元,使實(shí)際可用內(nèi)存減少,就好像內(nèi)存泄漏了一樣。

由substring方法引發(fā)的內(nèi)存泄漏

substring(int beginIndex, int endndex )是String類的一個(gè)方法,但是這個(gè)方法在JDK6和JDK7中的實(shí)現(xiàn)是完全不同的(雖然它們都達(dá)到了同樣的效果)。了解它們實(shí)現(xiàn)細(xì)節(jié)上的差異,能夠更好的幫助你使用它們,因?yàn)樵贘DK1.6中不當(dāng)使用substring會(huì)導(dǎo)致嚴(yán)重的內(nèi)存泄漏問題。

1、substring的作用

substring(int beginIndex, int endIndex)方法返回一個(gè)子字符串,從父字符串的beginIndex開始,結(jié)束于endindex-1。父字符串的下標(biāo)從0開始,子字符串包含beginIndex而不包含endIndex。

String x= "abcdef"; x= str.substring(1,3); System.out.println(x);"abcdef"; x= str.substring(1,3); System.out.println(x);

上述程序的輸出是“bc”

2、實(shí)現(xiàn)原理

String類是不可變變,當(dāng)上述第二句中x被重新賦值的時(shí)候,它會(huì)指向一個(gè)新的字符串對(duì)象,就像下面的這幅圖所示:

然而,這幅圖并沒有準(zhǔn)確說明的或者代表堆中發(fā)生的實(shí)際情況,當(dāng)substring被調(diào)用的時(shí)候真正發(fā)生的才是這兩者的差別。

JDK6中的substring實(shí)現(xiàn)

String對(duì)象被當(dāng)作一個(gè)char數(shù)組來存儲(chǔ),在String類中有3個(gè)域:char[] value、int offset、int count,分別用來存儲(chǔ)真實(shí)的字符數(shù)組,數(shù)組的起始位置,String的字符數(shù)。由這3個(gè)變量就可以決定一個(gè)字符串。當(dāng)substring方法被調(diào)用的時(shí)候,它會(huì)創(chuàng)建一個(gè)新的字符串,但是上述的char數(shù)組value仍然會(huì)使用原來父數(shù)組的那個(gè)value。父數(shù)組和子數(shù)組的唯一差別就是count和offset的值不一樣,下面這張圖可以很形象的說明上述過程。

看一下JDK6中substring的實(shí)現(xiàn)源碼:

public String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > count) {throw new StringIndexOutOfBoundsException(endIndex);}if (beginIndex > endIndex) {throw new StringIndexOutOfBoundsException(endIndex - beginIndex);}return ((beginIndex == 0) && (endIndex == count)) ? this :new String(offset + beginIndex, endIndex - beginIndex, value); //使用的是和父字符串同一個(gè)char數(shù)組value} String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > count) {throw new StringIndexOutOfBoundsException(endIndex);}if (beginIndex > endIndex) {throw new StringIndexOutOfBoundsException(endIndex - beginIndex);}return ((beginIndex == 0) && (endIndex == count)) ? this :new String(offset + beginIndex, endIndex - beginIndex, value); //使用的是和父字符串同一個(gè)char數(shù)組value} String(int offset, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;}set, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;}

由此引發(fā)的內(nèi)存泄漏泄漏情況:

String str = "abcdefghijklmnopqrst"; String sub = str.substring(1, 3); str = null;"abcdefghijklmnopqrst"; String sub = str.substring(1, 3); str = null;

這段簡(jiǎn)單的程序有兩個(gè)字符串變量str、sub。sub字符串是由父字符串str截取得到的,假如上述這段程序在JDK1.6中運(yùn)行,我們知道數(shù)組的內(nèi)存空間分配是在堆上進(jìn)行的,那么sub和str的內(nèi)部char數(shù)組value是公用了同一個(gè),也就是上述有字符a~字符t組成的char數(shù)組,str和sub唯一的差別就是在數(shù)組中其實(shí)beginIndex和字符長度count的不同。在第三句,我們使str引用為空,本意是釋放str占用的空間,但是這個(gè)時(shí)候,GC是無法回收這個(gè)大的char數(shù)組的,因?yàn)檫€在被sub字符串內(nèi)部引用著,雖然sub只截取這個(gè)大數(shù)組的一小部分。當(dāng)str是一個(gè)非常大字符串的時(shí)候,這種浪費(fèi)是非常明顯的,甚至?xí)硇阅軉栴},解決這個(gè)問題可以是通過以下的方法:

String str = "abcdefghijklmnopqrst"; String sub = str.substring(1, 3) + ""; str = null;"abcdefghijklmnopqrst"; String sub = str.substring(1, 3) + ""; str = null;

利用的就是字符串的拼接技術(shù),它會(huì)創(chuàng)建一個(gè)新的字符串,這個(gè)新的字符串會(huì)使用一個(gè)新的內(nèi)部char數(shù)組存儲(chǔ)自己實(shí)際需要的字符,這樣父數(shù)組的char數(shù)組就不會(huì)被其他引用,令str=null,在下一次GC回收的時(shí)候會(huì)回收整個(gè)str占用的空間。但是這樣書寫很明顯是不好看的,所以在JDK7中,substring 被重新實(shí)現(xiàn)了。

JDK7中的substring實(shí)現(xiàn)

在JDK7中改進(jìn)了substring的實(shí)現(xiàn),它實(shí)際是為截取的子字符串在堆中創(chuàng)建了一個(gè)新的char數(shù)組用于保存子字符串的字符。下面的這張圖說明了JDK7中substring的實(shí)現(xiàn)過程:

查看JDK7中String類的substring方法的實(shí)現(xiàn)源碼:

public String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > value.length) {throw new StringIndexOutOfBoundsException(endIndex);}int subLen = endIndex - beginIndex;if (subLen < 0) {throw new StringIndexOutOfBoundsException(subLen);}return ((beginIndex == 0) && (endIndex == value.length)) ? this: new String(value, beginIndex, subLen);} String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > value.length) {throw new StringIndexOutOfBoundsException(endIndex);}int subLen = endIndex - beginIndex;if (subLen < 0) {throw new StringIndexOutOfBoundsException(subLen);}return ((beginIndex == 0) && (endIndex == value.length)) ? this: new String(value, beginIndex, subLen);} public String(char value[], int offset, int count) {if (offset < 0) {throw new StringIndexOutOfBoundsException(offset);}if (count < 0) {throw new StringIndexOutOfBoundsException(count);}// Note: offset or count might be near -1>>>1.if (offset > value.length - count) {throw new StringIndexOutOfBoundsException(offset + count);}this.value = Arrays.copyOfRange(value, offset, offset+count);} String(char value[], int offset, int count) {if (offset < 0) {throw new StringIndexOutOfBoundsException(offset);}if (count < 0) {throw new StringIndexOutOfBoundsException(count);}// Note: offset or count might be near -1>>>1.if (offset > value.length - count) {throw new StringIndexOutOfBoundsException(offset + count);}this.value = Arrays.copyOfRange(value, offset, offset+count);}

Arrays類的copyOfRange方法:

public static char[] copyOfRange(char[] original, int from, int to) {int newLength = to - from;if (newLength < 0)throw new IllegalArgumentException(from + " > " + to);char[] copy = new char[newLength]; //是創(chuàng)建了一個(gè)新的char數(shù)組System.arraycopy(original, from, copy, 0,Math.min(original.length - from, newLength));return copy;} static char[] copyOfRange(char[] original, int from, int to) {int newLength = to - from;if (newLength < 0)throw new IllegalArgumentException(from + " > " + to);char[] copy = new char[newLength]; //是創(chuàng)建了一個(gè)新的char數(shù)組System.arraycopy(original, from, copy, 0,Math.min(original.length - from, newLength));return copy;}

可以發(fā)現(xiàn)是去為子字符串創(chuàng)建了一個(gè)新的char數(shù)組去存儲(chǔ)子字符串中的字符。這樣子字符串和父字符串也就沒有什么必然的聯(lián)系了,當(dāng)父字符串的引用失效的時(shí)候,GC就會(huì)適時(shí)的回收父字符串占用的內(nèi)存空間。

?

?

?

歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。

總結(jié)

以上是生活随笔為你收集整理的Java中由substring方法引发的内存泄漏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 中文资源在线播放 | 中文字幕第七页 | 狠狠操网站 | 99国产精品99久久久久久 | 丁香啪啪 | www.香蕉网 | 动漫精品一区 | 边添小泬边狠狠躁视频 | 欧美国产视频 | 欧美日韩免费在线观看 | 亚洲成人午夜影院 | 精品国产综合区久久久久久 | 高清中文字幕mv的电影 | 日韩欧美猛交xxxxx无码 | 一区二区视频在线观看 | 亚洲精品久久久久久无码色欲四季 | 爱福利视频网 | 国产欧美三级 | 成人免费在线播放视频 | 日本天堂在线视频 | 国产对白刺激视频 | 人体内射精一区二区三区 | 精品人妻二区中文字幕 | 国内激情| 亚洲综合精品在线 | 久久99精品国产麻豆婷婷洗澡 | 国产夫妻在线观看 | 不卡一区二区在线观看 | 亚洲一区二区三区乱码 | 国产精品成人电影在线观看 | 日韩av专区片 | 99精品人妻国产毛片 | 青青草视频免费看 | 黄色网免费观看 | 免费久久网站 | 中文字幕福利视频 | 一区二区三区久久精品 | 欧美成人精品欧美一级乱黄 | 日韩二级 | 国产无码久久精品 | 久久精品视频免费观看 | 日日插插| 午夜影院毛片 | av黄| 午夜a视频 | 少妇情理伦片丰满午夜在线观看 | 男人日女人在线观看 | 国产秋霞| 麻豆changesxxx国产 | 91精品91久久久中77777 | 最近日本中文字幕 | 日本一本久 | 亚洲精品国产精品国自产观看浪潮 | 又黄又色又爽的视频 | 中国一区二区视频 | 免费视频久久久 | 神马老子午夜 | 日日爱669| 日本一区二区视频免费 | 午夜18视频在线观看 | 超级变态重口av番号 | 精品在线小视频 | 特黄特色大片免费播放器使用方法 | 国产激情久久久久 | 国模人体一区二区 | av片免费 | 色丁香av | 久久久成人精品 | 国产美女引诱水电工 | 国产女人与zoxxxx另类 | 日韩中文字幕一区二区三区 | 午夜影视福利 | 美女十八毛片 | 欧美操穴 | 国产一区二区三区四区在线观看 | www.成年人 | 私密视频在线观看 | 日韩高清一级片 | 亚洲成人精品在线 | 国产精品久久久久野外 | 亚洲一区二区视频在线观看 | 欧日韩视频| 啪啪福利 | 国内精品毛片 | av电影免费在线播放 | 欧美色交| 国产剧情在线一区 | 韩国视频一区二区三区 | 白白色免费视频 | 国产在线免费 | 欧美日韩中文字幕一区二区 | 中文字幕在线观 | 日韩成人精品一区二区三区 | 国产美女黄色片 | 一区二区视屏 | 91丨porny丨首页 | 伊人啪啪| 久久国产乱子伦免费精品 | 国产小视频免费观看 |