Java高量的char [],如何减少?

Jir*_*ire 3 java garbage-collection

我相信当我new String在整个应用程序中的各个地方打电话时会产生这种垃圾.如何在不创建新对象的情况下"创建"字符串?

这种垃圾敏感的原因是因为我的应用程序无法创建垃圾,因为我们需要使用默认的Java GC接近实时运行.

// you can see I use the same chars array
public String getB37String() {
    long l = getLong();
    int i = 0;
    while (l != 0L) {
        long l1 = l;
        l /= 37L;
        chars[11 - i++] = validChars[(int) (l1 - l * 37L)];
    }
    return new String(chars, 12 - i, i);
}
Run Code Online (Sandbox Code Playgroud)

例如StringBuilder.toString(),使用new String下面使用的.

// and you can see that I use the same builder
public String getString() {
    builder.delete(0, builder.length());
    char ascii;
    while (0 != (ascii = (char) getUByte()) && backing.hasRemaining())
        builder.append(ascii);
    return builder.toString();
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*n C 6

首先观察一下:

这种垃圾敏感的原因是因为我的应用程序无法创建垃圾,因为我们需要使用默认的Java GC接近实时运行.

如果那个(" 不能创建垃圾")实际上是一个真正的声明1,那么你可能已经开始在错误的地方选择Java作为你的实现语言.

Java的设计基于垃圾的生成是可以的.这是避免执行显式内存管理的固有复杂性(以及随之而来的错误)的"成本".这种假设贯穿于语言设计和标准库设计中.

关于Java的另一个不是"对你有利"的事情是它强烈支持良好的面向对象设计原则.特别是,除少数例外情况外,API提供了强大的抽象功能,旨在防止应用程序意外破坏事物的陷阱.

例如,当您这样做时:

  char[] c = new char[]{'a', 'b', 'c'};
  ...
  String s = new String(c);
Run Code Online (Sandbox Code Playgroud)

String构造函数分配一个新的char[],并复制到字符c到它.为什么?因为如果没有,你会有一个"漏洞抽象".有人可以这样做:

  char[] c = new char[]{'a', 'b', 'c'};
  ...
  String s = new String(c);
  ...
  c[0] = 'd';
Run Code Online (Sandbox Code Playgroud)

泄漏的抽象导致了(假设的)不可变对象的变化.


那么什么是"解决方案"?

  1. 您可以使用C或C++或其他一些编程语言重写应用程序,您可以完全控制内存分配.(当然,这是很多工作......而且可能还有其他原因导致你无法做到这一点.)

  2. 您可以重新设计应用程序的相关部分,以便它们不使用String或者StringBuilder任何涉及显式或隐式(引擎盖下)堆分配的标准Java类.这不是不可能的,但它需要做很多工作.例如,许多标准和第三方API都希望您将它们String作为参数传递给它们.

  3. 您可以分析执行字符串操作的代码部分,使其"更智能",以减少垃圾分配.

不幸的是,所有这些都可能使你的代码库更大,更难阅读,更难调试和更难维护.


1 - 如果您真正想要解决的问题是GC暂停,则可能不是真的一种情况.有一些方法可以解决GC暂停问题,但这些问题并没有产生任何垃圾.例如,选择一个低暂停并行GC,并减小年轻代空间的大小,可能会给你一些短暂到不明显的停顿.另一个技巧是当你知道用户不会注意到时,强制GC点数; 例如,在游戏中加载新关卡时.