大家好,我是冰河~~
最近,一名小伙伴跟我說:他寫的程式在測驗環境一點問題沒有,但是發到生產環境卻會頻繁出現記憶體溢位的情況,這個問題都困擾他一周多了,于是乎,周末我便開始幫他排查各種問題,
如果文章對你有點幫助,小伙伴們點贊、收藏、評論和分享,走起呀~~
小伙伴的疑問

問題確定
排查問題的整個程序相當耗時,這里,我就直接說定位到的問題吧,后面,我會單獨寫一篇詳細的排查問題程序的文章!
在排查問題的程序中,我發現這位小伙伴使用的JDK還是1.6版本,開始,我也沒想那么多,繼續排查他寫的代碼,也沒找出什么問題,但是一旦啟動生產環境的程式,沒過多久,JVM就拋出了記憶體溢位的例外,
這就奇怪了,怎么回事呢?
啟動程式時加上合理的JVM引數,問題依然存在,,,
沒辦法,繼續看他的代碼吧!無意間,我發現他寫的代碼中,大量使用了String類的substring()方法來截取字串,于是,我便跟到JDK中的代碼查看傳遞進來的引數,
這無意間點進來的一次查看,竟然找到了問題所在!!
JDK1.6中String類的坑
經過分析,竟然發現了JDK1.6中String類的一個大坑!為啥說它是個坑呢?就是因為它的substring()方法會把人坑慘!不多說了,我們先來看下JDK1.6中的String類的substring()方法,
public String substring(int bedinIndex, 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);
}
接下來,我們來看看JDK1.6中的String類的一個構造方法,如下所示,
String(int offset, int count, char[] value){
this.value = value;
this.offset = offset;
this.count = count;
}
看到,這里,相信細心的小伙伴已經發現了問題,導致問題的罪魁禍首就是下面的一行代碼,
this.value = value;
在JDK1.6中,使用 String 類的建構式創建子字串的時候,并不只是簡單的拷貝所需要的物件,而是每次都會把整個value參考進來,如果原來的字串比較大,即使這個字串不再被應用,這個字串所分配的記憶體也不會被釋放, 這也是我經過長時間的分析代碼得出的結論,確實是太坑了!!
既然問題找到了,那我們就要解決這個問題,
升級JDK
既然JDK1.6中的String類存在如此巨大的坑,那最直接有效的方式就是升級JDK,于是,我便跟小伙伴說明了情況,讓他將JDK升級到JDK1.8,
同樣的,我們也來看下JDK1.8中的String類的substring()方法,
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);
}
在JDK1.8中的String類的substring()方法中,也呼叫了String類的構造方法來生成子字串,我們來看看這個構造方法,如下所示,
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// 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);
}
在JDK1.8中,當我們需要一個子字串的時候,substring 生成了一個新的字串,這個字串通過建構式的 Arrays.copyOfRange 函式進行構造,這個是沒啥問題,
優化JVM啟動引數
這里,為了更好的提升系統的性能,我也幫這位小伙伴優化了JVM啟動引數,
經小伙伴授權, 我簡單列下他們的業務規模和服務器配置:整套系統采用分布式架構,架構中的各業務服務采用集群部署,日均訪問量上億,日均交易訂單50W~100W,訂單系統的各服務器節點配置為4核8G,目前已將JDK升級到1.8版本,
根據上述條件,我給出了JVM調優后的引數配置,
-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M
至于,為啥會給出上述JVM引數配置,后續我會單獨寫文章來具體分析如何根據實際業務場景來進行JVM引數調優,
經過分析和解決問題,小伙伴的程式在生產環境下運行的很平穩,至少目前還未出現記憶體溢位的情況!!
結論
如果在程式中創建了比較大的物件,并且我們基于這個大物件生成了一些其他的資訊,此時,一定要釋放和這個大物件的參考關系,否則,就會埋下記憶體溢位的隱患,
JVM優化的目標就是:盡可能讓物件都在新生代里分配和回收,盡量別讓太多物件頻繁進入老年代,避免頻繁對老年代進行垃圾回收,同時給系統充足的記憶體大小,避免新生代頻繁的進行垃圾回收,
寫在最后
如果你想進大廠,想升職加薪,或者對自己現有的作業比較迷茫,都可以私信我交流,希望我的一些經歷能夠幫助到大家~~
推薦閱讀:
- 《實踐出真知:全網最強秒殺系統架構解密,不是所有的秒殺都是秒殺!!》
- 《從零到上億用戶,我是如何一步步優化MySQL資料庫的?(建議收藏)》
- 《我用多執行緒進一步優化了億級流量電商業務下的海量資料校對系統,性能再次提升了200%!!(全程干貨,建議收藏)》
- 《我用多執行緒優化了億級流量電商業務下的海量資料校對系統,性能直接提升了200%!!(全程干貨,建議收藏)》
- 《我用10張圖總結出了這份并發編程最佳學習路線!!(建議收藏)》
- 《高并發場景下一種比讀寫鎖更快的鎖,看完我徹底折服了!!(建議收藏)》
- 《全網最全性能優化總結!!(冰河吐血整理,建議收藏)》
- 《三天擼完了MyBatis,各位隨便問!!(冰河吐血整理,建議收藏)》
- 《奉勸那些剛參加作業的學弟學妹們:要想進大廠,這些并發編程知識是你必須要掌握的!完整學習路線!!(建議收藏)》
- 《奉勸那些剛參加作業的學弟學妹們:要想進大廠,這些核心技能是你必須要掌握的!完整學習路線!!(建議收藏)》
- 《奉勸那些剛參加作業的學弟學妹們:這些計算機與作業系統基礎知識越早知道越好!萬字長文太頂了!!(建議收藏)》
- 《我用三天時間開發了一款老少皆宜的國民級游戲,支持播放音樂,現開放完整源代碼和注釋(建議收藏)!!》
- 《我是全網最硬核的高并發編程作者,CSDN最值得關注的博主,大家同意嗎?(建議收藏)》
- 《畢業五年,從月薪3000到年薪百萬,我掌握了哪些核心技能?(建議收藏)》
- 《我入侵了隔壁妹子的Wifi,發現,,,(全程實戰干貨,建議收藏)》
- 《千萬不要輕易嘗試“熊貓燒香”,這不,我后悔了!》
- 《清明節偷偷訓練“熊貓燒香”,結果我的電腦為熊貓“獻身了”!》
- 《7.3萬字肝爆Java8新特性,我不信你能看完!(建議收藏)》
- 《在業務高峰期拔掉服務器電源是一種怎樣的體驗?》
- 《全網最全Linux命令總結!!(史上最全,建議收藏)》
- 《用Python寫了個工具,完美破解了MySQL!!(建議收藏)》
- 《SimpleDateFormat類到底為啥不是執行緒安全的?(附六種解決方案,建議收藏)》
- 《MySQL 8中新增的這三大索引,直接讓MySQL起飛了,你竟然還不知道!!(建議收藏)》
- 《擼完Spring原始碼,我開源了這個分布式快取框架!!(建議收藏)》
- 《億級流量高并發秒殺系統商品“超賣”了,只因使用的JDK同步容器中存在這兩個巨大的坑!!(踩坑實錄,建議收藏)》
- 《奉勸那些剛參加作業的學弟學妹們:要想學好并發編程,這些并發容器的坑是你必須要注意的!!(建議收藏)》
- 《公司的報表工具太難用,我三天擼了個Excel工具,運營小姐姐直呼太好用了,現已開源!!(建議收藏)》
好了,今天就到這兒吧,小伙伴們點贊、收藏、評論,一鍵三連走起呀,我是冰河,我們下期見~~

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/300029.html
標籤:其他
上一篇:深度學習基礎之三分鐘輕松搞明白tensor到底是個啥!看不懂的話我倒立洗頭~~
下一篇:究竟死了幾條狗?
