字符串是软件开发中最为重要的对象之一。通常,字符串对象或者其等价对象,在内存中总是占据了最大的空间块。因此如何高效地处理字符串,必将是提高系统整体性能的关键所在。
String对象及其特点
String对象是Java中重要的数据类型,它不是基础数据类型。在Java中,String对象可以认为是char数组的延伸和进一步封装。下图展示了Java中String类的基本实现,它主要由3部分组成:char数组、偏移量和String的长度。 char数组表示String的内容,它是String对象所表示的字符串的超集。String的真实内容还需要借助偏移量和长度在这个char数组中进行定位和截取。
String对象有3个基本特点:
不变性
不变性是指String对象一旦生成,则不能再对它进行改变。
针对常量池的优化
当两个String对象拥有相同的值时,它们只引用常量池中的同一个拷贝。当同一个字符串反复出现时,这个技术可以大幅度节省内存空间。
类的final定义
作为final类的String对象,在系统中不可能有任何子类,这是对系统安全性的保护。
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);
}
// 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;
}
在方法最后,返回了一个新建的String对象。查看该String的构造函数以及函数注释可知,这是一个包作用域的构造函数,其目的是为了高效快速地共享char数组。
但在这种通过偏移量和长度来定位和截取字符串的方法中,String的原生内容value数组被整个复制到新的子字符串中。设想,如果原生字符串很大,截取的字符串长度却很短,那么截取的子字符串中却包含了整个原生字符串的所以内容,并占据了相应的内存空间,而仅仅通过偏移量和长度来定位和截取真实内容。
提高了运算速度,浪费了大量的内存空间。典型的空间换时间!
下面以一个实例来说明内存泄露的情况:
static class HugeString {
private String str = new String(new char[100000]);
public String getSubStr(int beginIndex, int endIndex) {
return str.substring(beginIndex, endIndex);
}
}
static class ImprovedHugeString {
private String str = new String(new char[100000]);
public String getSubStr(int beginIndex, int endIndex) {
return new String(str.substring(beginIndex, endIndex));
}
}
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 1000; i++) {
//HugeString hugeString = new HugeString();
ImprovedHugeString hugeString = new ImprovedHugeString();
list.add(hugeString.getSubStr(0, 5));
}
System.out.println("over");
}
ImprovedHugeString类的实例不会引发内存泄露的原因是因为其重新调用了没有内存泄露风险的构造函数,对需要占用的内存空间进行了重新整理。释放了substring方法返回的、存在内存泄露的String对象的强引用,以便其能被GC回收。如下所示:
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;
}
分享到:
相关推荐
Java程序性能优化 笔记 脑图
Java字符串学习笔记,比较系统的讲解了Java的字符串知识
性能优化手册是一套java性能学习研究小技巧,包含内容:Java性能优化、JVM性能优化、服务器性能优化、数据库性能优化、前端性能优化等。 内容包括但不限于: String 性能优化的 3 个小技巧 HashMap 7 种遍历方式...
本文档是Xingyu在Android软件开发过程中的随手笔记,主要对字符串的一些常规用法作了随手记录,以备后忘,没什么技术含量, 对初学者有一定参考作用,高手就不要下了。
java中equals和'=='区别以及与字符串相关的几个函数介绍
python字符串学习笔记.python字符串操作方法
别下别下别下别下别下别下别下别下别下别下别下别下别下别下别下别下别下别下
Java程序设计个人所整理的一些笔记
《嵌入式Linux C语言应用程序设计》读书笔记《嵌入式Linux C语言应用程序设计》读书笔记《嵌入式Linux C语言应用程序设计》读书笔记《嵌入式Linux C语言应用程序设计》读书笔记《嵌入式Linux C语言应用程序设计》...
java 中关于字符串的笔记,超级详细,在培训中心整理的
JAVA程序设计学习笔记.pdf
内容源自清华大学出版的《Java程序设计习题集》,小弟将自己做题的笔记整理了一部分,与各位分享,请勿用于商业目的!谢谢
Java优化编程(第2版)通过丰富、完整、富有代表性的实例,展示了如何提升Java应用性能,并且给出了优化前与优化后的Java应用程序的性能差别,以实际的实例与数字告诉你,为什么不可以这么做,应该怎么做,深入分析...
java笔记java笔记java笔记java笔记java笔记java笔记java笔记
java学习笔记java学习笔记java学习笔记java学习笔记
java程序抽象类讲解笔记
Java语言程序设计学习笔记,配套的md文件,查找起来方便一些
Java秒杀系统方案优化-高性能高并发实战 Java秒杀系统方案优化-高性能高并发实战
Java游戏编程读书笔记,Java游戏编程读书笔记
Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记