java-subString方法易导致内存溢出

简介: String.substring(int beginIndex, int endIndex)方法来截取字串,但是该方法为了节约时间,提升性能,浪费了大量空间,其源代码如下public String substring(int beginIndex, in...

String.substring(int beginIndex, int endIndex)方法来截取字串,但是该方法为了节约时间,提升性能,浪费了大量空间,其源代码如下

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对象,查看该构造函数源码如下:

String(int offset, int count, char value[]) {  
    this.value = value;  
    this.offset = offset;  
    this.count = count;  
    }  

其只是通过偏移量来获取一个字符数组的子数组,但是原数组中,没有被选择的并没有及时释放,因此,如果原字符串很长,而需要的子字符串又很短,则很容易造成内存溢出,如以下代码:

public class SubStringTest {  

    public static void main(String[] args) {  
        List<String> handlerList = new ArrayList<String>();  
        /* 
         * HugeStr不到100000次就内存溢出 但是ImprovedHuge不会 
         */  
        for (int i = 0; i < 100000; i++) {  
            HugeStr h = new HugeStr();  
            handlerList.add(h.getSubString(1, 5));  
            System.out.println("times:"+i);  
        }  

    }  

    static class HugeStr {  
        private String str = new String(new char[100000]);  

        // 一个很长的字符串  
        public String getSubString(int begin, int end) {  
            // 获取字符串,有溢出  
            return str.substring(begin, end);  
        }  
    }  

解决方案x = new String(x.substring(x, y));这样的话,就会创建一个新数组,切断与原来的数组的引用,既然JDK6中存在这样一个鸡肋,SUN工程师们肯定会解决的,在JDK7中,该鸡肋已经得到解决。在JDK7中调用substring时,会自动创建一个字符数组,新字符串指向新字符数组,则原来数组可以被GC处理。

//JDK 7  
public String(char value[], int offset, int count) {  
    //check boundary  
    this.value = Arrays.copyOfRange(value, offset, offset + count);  
}  

public String substring(int beginIndex, int endIndex) {  
    //check boundary  
    int subLen = endIndex - beginIndex;  
   return new String(value, beginIndex, subLen);  
String x = "abcdef";  
x = x.substring(1,3);
目录
相关文章
|
14天前
|
存储 Java 编译器
Java内存区域详解
Java内存区域详解
29 0
Java内存区域详解
|
24天前
|
缓存 算法 Java
Java内存管理与调优:释放应用潜能的关键
【4月更文挑战第2天】Java内存管理关乎性能与稳定性。理解JVM内存结构,如堆和栈,是优化基础。内存泄漏是常见问题,需谨慎管理对象生命周期,并使用工具如VisualVM检测。有效字符串处理、选择合适数据结构和算法能提升效率。垃圾回收自动回收内存,但策略调整影响性能,如选择不同类型的垃圾回收器。其他优化包括调整堆大小、使用对象池和缓存。掌握这些技巧,开发者能优化应用,提升系统性能。
|
15天前
|
Java
Java中ReentrantLock中tryLock()方法加锁分析
Java中ReentrantLock中tryLock()方法加锁分析
13 0
|
4天前
|
Java 关系型数据库 MySQL
Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
【4月更文挑战第12天】Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
30 3
|
20天前
|
缓存 安全 Java
Java并发编程进阶:深入理解Java内存模型
【4月更文挑战第6天】Java内存模型(JMM)是多线程编程的关键,定义了线程间共享变量读写的规则,确保数据一致性和可见性。主要包括原子性、可见性和有序性三大特性。Happens-Before原则规定操作顺序,内存屏障和锁则保障这些原则的实施。理解JMM和相关机制对于编写线程安全、高性能的Java并发程序至关重要。
|
1天前
|
Java
Java 与垃圾回收有关的方法
Java 与垃圾回收有关的方法
|
2天前
|
Java 程序员 数据库连接
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
|
2天前
|
存储 Java 测试技术
一文搞清楚Java中的方法、常量、变量、参数
在JVM的运转中,承载的是数据,而数据的一种变现形式就是“量”,量分为:**常量与变量**,我们在数学和物理学中已经接触过变量的概念了,在Java中的变量就是在程序运行过程中可以改变其值的量。
12 0
|
2天前
|
存储 安全 Java
滚雪球学Java(19):JavaSE中的内存管理:你所不知道的秘密
【4月更文挑战第8天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 4
滚雪球学Java(19):JavaSE中的内存管理:你所不知道的秘密
|
6天前
|
存储 Java
Java动态转发代理IP的实现方法
Java动态转发代理IP的实现方法
22 11