《java程序性能优化》读书笔记之字符串优化

字符串是软件开发中最为重要的对象之一。通常,字符串对象或者其等价对象,在内存中总是占据了最大的空间块。因此如何高效地处理字符串,必将是提高系统整体性能的关键所在。

[b]String对象及其特点[/b]

String对象是Java中重要的数据类型,它不是基础数据类型。在Java中,String对象可以认为是char数组的延伸和进一步封装。下图展示了Java中String类的基本实现,它主要由3部分组成:char数组、偏移量和String的长度。 char数组表示String的内容,它是String对象所表示的字符串的超集。String的真实内容还需要借助偏移量和长度在这个char数组中进行定位和截取。


[b]String对象有3个基本特点:[/b]

不变性
不变性是指String对象一旦生成,则不能再对它进行改变。

针对常量池的优化
当两个String对象拥有相同的值时,它们只引用常量池中的同一个拷贝。当同一个字符串反复出现时,这个技术可以大幅度节省内存空间。

类的final定义
作为final类的String对象,在系统中不可能有任何子类,这是对系统安全性的保护。

[b]substring()方法的内存泄露[/b]

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值