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);
目录
相关文章
|
2月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
277 3
|
3月前
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
1月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
63 4
|
1月前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
220 18
|
1月前
|
弹性计算 定位技术 数据中心
阿里云服务器配置选择方法:付费类型、地域及CPU内存配置全解析
阿里云服务器怎么选?2025最新指南:就近选择地域,降低延迟;长期使用选包年包月,短期灵活选按量付费;企业选2核4G5M仅199元/年,个人选2核2G3M低至99元/年,高性价比爆款推荐,轻松上云。
137 11
|
1月前
|
存储 缓存 Java
【深入浅出】揭秘Java内存模型(JMM):并发编程的基石
本文深入解析Java内存模型(JMM),揭示synchronized与volatile的底层原理,剖析主内存与工作内存、可见性、有序性等核心概念,助你理解并发编程三大难题及Happens-Before、内存屏障等解决方案,掌握多线程编程基石。
|
1月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
196 4
|
2月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
134 11
|
1月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
262 5
|
2月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。

热门文章

最新文章

下一篇
oss云网关配置