Java String.substring内存泄露?
2019独角兽企业重金招聘Python工程师标准>>>
String可以说是最常用的Java类型之一了,但是最近听说JDK6里面String.substring存在内存泄露的bug,伙惊呆!一起来看看到底是啥情况吧。
这个是可以导致Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 的代码:
public class TestGC {private String largeString = new String(new byte[100000]);String getString() { return this.largeString.substring(0, 2);//在JDK6里会导致out of memory,在JDK7和8不会出现问题// return new String("ab");// return this.largeString.substring(0,2) + "";//JDK6下的解决方法,不会出现out of memory// return new String(this.largeString.substring(0, 2));/JDK6下的解决方法,不会出现out of memory} public static void main(String[] args) {java.util.List<String> list = new java.util.ArrayList<String>(); for (int i = 0; i < 100000; i++) {TestGC gc = new TestGC();list.add(gc.getString());}System.out.println("over" + list.size());}
}
但是用JDK8运行,平安无事。注意,之前看的网上文章又说安装了JDK8,只需要在Eclipse里面选Compiler选项为JDK6就可以了,我实 验是不可以的,自己想想String是JDK里面rt.jar的类,就算是编译为JDK6的代码,运行的时候还是用的JDK8的String啊,所以无法 复现bug才是正常的。要复现,只能下载安装JDK6.
有人认为这个会out of memory是因为TestGC对象里面有很大largeString的对象,但是其实在调用getString方法后,TestGC对象完全可以被回收 的,largeString也可以回收,JVM的自动垃圾回收应该不会有bug吧,不然还得了!将getString方法改为直接返回一个String对 象,就可以看出,不会有问题。
现在来看看为什么JDK6里面,substring会导致错误呢。Ctrl+B(IDEA的查看源码快捷键点进去看下),代码如下
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);}
前面几行主要是做范围检查,最主要的是
new String(offset + beginIndex, endIndex - beginIndex, value);
String(int offset, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;
}
可以看到JDK6里的substring复用了原来大String的整个value,即String里存放实际char的数组
/** The value is used for character storage. */private final char value[];
而只是通过修改beginIndex和offset来达到复用value,避免数组copy的麻烦(以及可以提高一点性能),但是问题就是,如果原 String很大,而substring保留的时间比较久,就有可能导致整个很大的value无法回收。JDK6下的修复方法就是,强制生成一个新的 String,避免复用原来String里的value,比如:
return this.largeString.substring(0,2) + "";//JDK6下的解决方法,不会出现out of memory
其实,这恰恰也是JDK8里面的实现方式。上src:
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) { 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);}
可以看到,最后对value做了数组copy。
其实JDK8的修改也是褒贬不一,也有人认为JDK6里面的实现方法更好,效率更高,只要自己注意就可以避免问题的,这就是仁者见仁智者见智的问题了,只是需要知道,JDK6里String的这个小坑就好。
参考文章
http://droidyue.com/blog/2014/12/14/substring-memory-issue-in-java/
http://www.programcreek.com/2013/09/the-substring-method-in-jdk-6-and-jdk-7/
转载于:https://my.oschina.net/magicly007/blog/497227
Java String.substring内存泄露?相关推荐
- String.subString内存泄露
在jdk6中,substring还是指向原来的字符串,可以用 new String(str.substring())避免内存泄露 在jdk7中,没有这个问题
- Java中的内存泄露的几种可能
转载自 Java中的内存泄露的几种可能 Java内存泄漏引起的原因: 内存泄漏是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏. 长生命周 ...
- Java String substring()方法示例
Java String substring() method returns the substring of this string. This method always returns a ne ...
- java程序会发生内存泄露吗及内存泄漏场景
java程序会发生内存泄露的问题吗?请简单说说你的观点 答案:会.Java内存管理是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收的,java程序员不需要通过调用函数来 ...
- java string.substring 参数,Java,String类中的subString()方法,stringsubstring
Java,String类中的subString()方法,stringsubstring public class TestStringSubString { // main函数 public stat ...
- java string占用内存_Java中String到底占用多大的内存空间?
写在前面 对于Java中的String类占用多大的内存空间这个问题,是最近面试中问的比较多的一个问题.很多小伙伴的回答的都不是很正确,有说不占空间的,有说1个字节的,有说2个字节的,有说3个字节的,有 ...
- java 堆外内存泄露排查
参考:http://blog.itpub.net/70016482/viewspace-2908649/ 一.原理 JDK提供绕过JVM直接在操作系统申请内存的接口,例如通过Unsafe类的alloc ...
- Java堆外内存泄露分析
查看堆内存占用正常,jvm垃圾回收也没有异常.而top出来显示java占用内存是几个G,那么可能想到了是堆外内存泄漏. 需要安装google-perftools工具进行分析 1.先安装g++ 不然编译 ...
- java方法区内存泄露_深入理解java虚拟机-第二章:java内存区域与内存泄露异常...
2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...
最新文章
- 周志华教授:AI领域如何做优秀研究并写高水平论文?
- Wireshark默认不抓取本地包的解决方式
- 6.(Mysql数据管理相关)连接MYSQL,修改密码,增加新用户,数据库相关命令,表操作相关命令,数据相关命令,数据库sql导入和导出,备份数据库,查看不到mysql数据库的解决办法
- 【数据结构与算法】之深入解析“串联所有单词的子串”的求解思路与算法示例
- 【Flask】jinja2根据url中的字符串,决定是否显示某个div
- 三维错切变换矩阵_图像的仿射变换
- (转) android UI进阶之用gallery实现可滑动的Tab
- java第一章_java 第一章
- 大数据的趋势走向如何
- 第九次作业(杨辉三角)
- angularjs(显示和隐身) 依赖注入
- 万能打印之Delphi 2010实现(一)
- 基于Matlab的极限学习机(ELM)实现
- cp105b linux 驱动,富士施乐 DocuPrint CP105b驱动
- python图像风格迁移_Python 超简单实现9种图像风格迁移
- 乐高叉车wedo教案_特色课程——乐高wedo动力机械
- 立秋养生,老话说“三不吃、三不做、三不睡”,精神饱满健康过秋
- ZABBIX 钉钉报警 插件(python)
- 【懒人必备神器】教你用Python做一个自动抽奖程序啦~
- 什么是流批一体化、区块链
热门文章
- ptam tracking
- Spring源码分析【1】-Tomcat的初始化
- Windows7/10上配置OpenCV3.3.0-Python3.6.2操作步骤
- CUDA Samples:Vector Add
- 深度学习开源库tiny-dnn的使用(MNIST)
- matlab常遇小问题汇总
- 【杂】突然有个想法,为了防止公司或其他,监视你的qq或微信,可以做个程序,将信息打乱,分别用qq和微信传输,然后,再还原
- 【OpenCV】使用过的函数汇总
- 因子分析数据_Excel数据分析案例:用Excel做因子分析
- 7-5 二分法求多项式单根 (20分)