String中substring方法内存泄漏问题
众所周知,JDK中以前String类中的substring方法存在内存泄漏问题,之所以说是以前,是因为JDK1.7及以后的版本已经修复了,我看都说JDK1.6的版本也存在这个问题,但是我本机上安装的1.6看了看源码不存在内存泄漏问题啊,又看了1.7的源码,和我本机的1.6的一样,是不是我的1.6版版其实是1.7的?!唉,不管了,反正1.7版本肯定没有这个问题(1.5及更老版本肯定有)了,大家就放心的用吧。
之所以存在内存泄漏的问题,是因为原先的版本中,substring是这样实现的:
- 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);
- }
而其中用到的String构造方法是这样的:
- // Package private constructor which shares value array for speed.
- String(int offset, int count, char value[]) {
- this.value = value;
- this.offset = offset;
- this.count = count;
- }
this.value=value这种实现就出现问题了,因为String类中有几个私有的成员变量:
- /** 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;
-
- /** The count is the number of characters in the String. */
- private final int count;
-
- /** Cache the hash code for the string */
- private int hash; // Default to 0
明白了吧,这种实现还在引用着原先字符串变量的value[],通过offset和count返回一个长得像的“截取”后的字符串给人一种错觉,导致JVM认为这个最初字符串还在被引用着不对其gc,不过之所以这么做SUN公司(oracle 10年收购了)的JDK编写人员也是有原因的,就是效率问题,如注释所说:
Package private constructor which shares value array for speed.
这样导致的后果就是如果有一个很大很长的字符串我只需要其中的一小部分字符串用substring实现的话,如果让你看似得到的“新”的短小字符串一直没被JVM 回收的话,那么相当这个最初的大字符串也没被回收,尤其是你把这个短小“新”的字符串直接以引用的形式付给一个静态的全局变量,在加上如果访问数量很大,那应该“代价”还是蛮可观的,不过可以简单的这样new(s.substring())就避免了这个问题。
新的JDK中substring之所以不存在这个问题了,是因为这个构造方法改成这样了:
- 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.offset = 0;
- this.count = count;
- this.value = Arrays.copyOfRange(value, offset, offset+count);
- }
其中 value变量不再引用了而是重新新建了一个,所以没有这个问题了,是不是大家看完之后对这个方法有了更全新的认识?
转载请注明—作者:Java我人生(陈磊兴) 原文出处:http://blog.csdn.net/chenleixing/article/details/43646255
最后,认真看过的网友们,大神们,如有感觉我这个程序猿有哪个地方说的不对或者不妥或者你有很好的
提议或者建议或点子方法,还望您大恩大德施舍n秒的时间留下你的宝贵文字(留言),以便你,我,还有广大的程序猿们更快地成长与进步.......
相关文章
- C++ 遍历进程内存块
- android内存释放处理
- win11内存完整性打不开的解决方法
- Stream:测试服务器内存memory性能
- Linux 下查看某一个程序所使用的内存方法
- 检测 Linux 内存使用情况的 free 命令的10个例子
- qt中的进程优先级及应用内存大小设置方法,VS和Qt工程中申请超过2G的内存的方法
- linux如何管理物理内存?
- Linux系统如何查看内存
- 快速定位性能瓶颈,检查出所有资源(CPU、内存、磁盘IO等)的利用率(utilization)、饱和度(saturation)和错误(error)度量,即USE方法
- JVM_01 内存结构(程序计数器、虚拟机栈、本地方法栈)
- JNI手动释放内存(避免内存泄露)
- JVM内存溢出环境备份方法
- 内存对齐是什么-对齐的本质是位置和大小-主语是结构体
- set方法的内存管理细节
- iOS高级教程:处理1000张图片的内存优化
- SetProcessWorkingSetSize() 方法使内存降低了很多(把内存放到交换区,其实会降低性能)——打开后长时间不使用软件,会有很长时间的加载过程,原来是这个!
- C++ 内存拷贝函数 memcpy
- JavaScript也谈内存优化
- javascript中的内存管理
- 介绍 Java 的内存泄漏
- Windows下MySQL service manager数据库/mysqld.exe占用内存解决方法/Workbench 10061错误/Navicat 10038错误
- delphi 自定义内存管理