String的构造

首先了解下String的构造,String内部使用char [] value 来存储字符。
需要注意 offset和count在1.7已经没有了。

 /** The value is used for character storage. */private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;//仅仅出现在1.7以下/** The count is the number of characters in the String. */
private final int count;//仅仅出现在1.7以下

测试用例

环境: jdk1.6  之后为jdk1.7
运行参数  这里指定了最大堆为50m . 如果list仅仅存(5-1)*100个字符 应该是完全没问题的。
`-Xms50m -Xmx50m -XX:+PrintGCDetails`public class MyTest {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {List list = new ArrayList<>();for (int i = 0; i < 100; i++) {list.add(new HugeStr().getSub());
//            list.add(new ImprovedHugeStr().getSub());}Object o = list.get(99);Field value = String.class.getDeclaredField("value");value.setAccessible(true);Object o1 = value.get(o);if (o1 instanceof char[]) {System.out.println(((char[]) o1).length);}}public static class HugeStr{private String str = new String(new char[1024*1024]);public String getSub(){return str.substring(1, 5);//1.7已经修复, 内部采用Arrays.copyOfRange}}public static class ImprovedHugeStr{private String str = new String(new char[1024*1024]);public String getSub(){return new String(str.substring(1, 5));//new String的时候会使用Arrays.copyOfRange 拷贝需要的部分。}}
}

jdk1.6 String代码部分实现

需要注意subString时传入的value是原字符串的char [] value.
new String 时,判断了offset与count.通过 Arrays.copyOfRange生成字符数组。

    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);//此处value储存有原字符串的所有字符①}// Package private constructor which shares value array for speed.String(int offset, int count, char value[]) {//subString最终调用此方法②this.value = value;this.offset = offset;this.count = count;}public String(String original) {int size = original.count;char[] originalValue = original.value;char[] v;if (originalValue.length > size) {// The array representing the String is bigger than the new// String itself.  Perhaps this constructor is being called// in order to trim the baggage, so make a copy of the array.int off = original.offset;v = Arrays.copyOfRange(originalValue, off, off+size);//③此处保证修复后的代码不再泄露 } else {// The array representing the String is the same// size as the String, so no point in making a copy.v = originalValue;}this.offset = 0;this.count = size;this.value = v;}

由上面代码可以知道。当使用HugeStr的getSub的时候,str.subString(1,5)返回的子串包含了原字符串的char数组 value.

jdk1.6中使用测试subString

①处 subString的value (v)和②处value代表原字符串str 的字符数组(长度大于4)。由于v的长度远大4,所以很快就内存不够,当内存不够发生gc的时候,v一直被子串b引用,导致无法回收。所以会报OOM。
看下测试效果:

一个子串包含了原字符串的所有char,1024*1024=148576

jdk1.6中使用修复后的代码测试subString

而ImprovedHugeStr的gutSub的时候, 实际在new String(str.substring(1, 5));的时候,返回的Arrays.copyOfRange拷贝的值(③)。已经失去了原字符串str 包括其value的引用,即使原字符串的value 很大,但是已经不被GC Roots对象链接到,会被回收。区区4长度*100的字符串, 不会引起OOM.
效果如图:

JDK1.7中已经修复了该问题

在new String内部使用了 Array.copyOfRange 拷贝。 原value 不再引用。当内存不够发生gc的时候,原value被回收。

jdk1.7 String代码部分实现

关键在 subString后调用的构造方法有改变。也是通过Arrays.copyOfRange拷贝。

    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);}public String(char value[], int offset, int count) {//subString最终调用此构造方法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);//此处是关键}public String(String original) {this.value = original.value;//1.7的构造方法有改变。  成员不再有 count,offsetthis.hash = original.hash;
}

测试效果:

参考

Java中的substring真的会引起内存泄露么?

《Java程序性能优化》subString()方法的内存泄露相关推荐

  1. java程序性能优化(实例)

    java程序性能优化(实例) 一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: i ...

  2. Java程序性能优化——设计优化

    原文出自:http://blog.csdn.net/anxpp/article/details/51914119,转载请注明出处,谢谢! 1.前言 OK,之前写了一篇文章:"23种设计模式介 ...

  3. Java程序性能优化——性能调优层次

    为了提升系统性能,开发人员可以从系统的各个角度和层次对系统进行优化.除了最常见的代码优化外,在软件架构上.JVM虚拟机层.数据库以及操作系统层都可以通过各种手段进行调优,从而在整体上提升系统的性能. ...

  4. Java程序性能优化-概述

    前言     这两天在看<Java程序性能优化>这本书,将我学到的书上好的东西分享给大家.做过开发的人应该或多或少都碰到过性能问题,遇到性能问题你是怎么做的呢?你能看懂程序的性能吗?本篇给 ...

  5. Java程序性能优化 读书笔记(十)并行设计模式:Future模式

    转载:Java多线程编程中Future模式的详解<转> 参考:葛一鸣,Java程序性能优化.清华大学出版社. 随着多核时代的到来,CPU的并行能力有了很大的提升.在这种背景下,传统的串行程 ...

  6. 开源即巅峰,《Java程序性能优化实战》GitHub三小时标星已超34k

    蓦然回首自己做开发已经十年了,这十年中我获得了很多,技术能力.培训.出国.大公司的经历,还有很多很好的朋友.但再仔细一想,这十年中我至少浪费了五年时间,这五年可以足够让自己成长为一个优秀的程序员,可惜 ...

  7. 滴滴架构师被迫离职后,只留下这份731页Java程序性能优化手册

    滴滴资深架构师深度分享Java程序性能优化的宝贵经验,从软件设计.编码和JVM等维度阐述性能优化的方法和技巧. 总览: 篇幅限制,这里就不全部展示出来了.需要获取完整版Java程序性能优化手册的小伙伴 ...

  8. Java 程序性能优化《第一章》Java性能调优概述 1.4小结

    Java 程序性能优化<第一章>1.4小结 通过本章的学习,读者应该了解性能的基本概念及其常用的参考指标.此外,本章还较为详细的介绍了与性能调优相关的两个重要理论--木桶原理以及Amdah ...

  9. java程序性能优化(一)

    根据<java程序性能优化>整理 字符串的分割和查找,在日常编码中很常见,平时使用最多的split()函数,但是也有一些更优的选择,下面就让我来一一对比: 上面的这个就是常用的split( ...

  10. 《Java程序性能优化》

    第一章 Java性能调优概述 1.1 性能概述 1.性能指标:执行时间.CPU时间.内存分配.磁盘吞吐量.网络吞吐量.响应时间:切记木桶原理 2.Amdahl定理:它定义了串行系统并行化后加速比的计算 ...

最新文章

  1. 用IE重起计算机或者关机
  2. php iis6 安装ssl证书,在IIS下部署SSL证书实现HTTPS
  3. 干货 | MTCNN实时人脸检测网络详解与代码演示
  4. 横扫六大权威榜单,达摩院自家深度语言模型体系AliceMind开源了
  5. Kubernetes 弹性伸缩全场景解析 (一):概念延伸与组件布局
  6. Best jQuery Plugins of 2010
  7. Matlab实用程序--图形应用-双y轴图形的绘制
  8. cpythonjavagolang_cpython:列表对象(PyListObject)的扩容机制
  9. 前端学习(2478):请求提交
  10. 实体与属性间的划分原则
  11. FZU2218 Simple String Problem(状压DP)
  12. c语言数组读心术,无聊的时候写的读心术小程序
  13. 手机信令数据怎么获得_手机信令数据辅助下的张江科学城职住分析及对策 | 上海城市规划...
  14. 分布式系统「伸缩性」大招之——「弹性架构」详解
  15. SHELL中获取函数返回值
  16. 尚观嵌入式c语言视频教程
  17. cactiEZ 配置
  18. layui框架引入TP教程
  19. freeradius 3.0 mysql_求助FreeRadius+MySql 配置
  20. 计算机硬件硬盘分区,电脑硬盘分几个区最好?电脑硬盘分区教程

热门文章

  1. 用最通俗的语言和例子,讲解网络编程的一些基本概念
  2. 财经365内参|央行:货币政策工具箱开得再大一些
  3. spmak matlab,Matlab样条工具箱(Spline ToolBox)与曲线拟合 - wuzoujing的...
  4. nlp数据增强-back translation
  5. 云原生爱好者周刊:PromLabs 开源 PromQL 可视化工具 PromLens
  6. 得物键盘-定制款三模机械键盘说明书(2023)
  7. Unity 桌面精灵+鼠标穿透
  8. CE简单修改演示(扫雷)
  9. 安全通用要求之安全物理环境
  10. 搭载骁龙865 realme发布旗下首款5G旗舰