繁体   English   中英

为什么我们有字符串池时的字符串重复数据删除

[英]Why String Deduplication when we have String Pool

字符串重复数据删除

字符串在任何应用程序中都占用大量内存。每当垃圾收集器访问String对象时,它都会记录char数组。 它接受它们的哈希值并将其与对数组的弱引用一起存储。 一旦找到另一个具有相同哈希码的String,就会将它们与char进行比较。如果它们匹配,则会修改一个String并指向第二个String的char数组。 然后不再引用第一个char数组,并且可以进行垃圾回收。

字符串池:

java程序使用的所有字符串都存储在此处。 如果两个变量初始化为相同的字符串值。 内存中没有创建两个字符串,只有一个副本存储在内存中,两个副本都指向相同的内存位置。

因此,java已经通过检查字符串池中是否存在字符串来解决不在堆中创建重复字符串的问题。 那么字符串重复数据删除的目的是什么?

如果有如下代码

    String myString_1 = new String("Hello World");
    String myString_2 = new String("Hello World");

即使它们是相同的,也会在内存中创建两个字符串。 除了这个字符串重复数据删除很有用之外,我想不出任何其他情况。 显然我必须遗漏一些东西。 我错过了什么?

提前致谢

串池适用于加入到它明确,或用作应用常量字符串。 并不适用于应用程序的生命周期中动态创建的字符串。 但是,字符串重复数据删除适用于所有字符串。

字符串重复数据删除享有String内置的额外间接级别:

  • 使用字符串池,您只能为两个相同的字符串返回相同的对象
  • 字符串重复数据删除允许您拥有共享相同内容的多个不同的String对象。

这转化为消除了对创建的重复数据删除的限制:您的应用程序可以继续创建具有相同内容的新String对象,同时使用非常少的额外内存,因为字符串的内容将被共享。 此过程可以在完全不相关的计划上完成 - 例如,在后台,而您的应用程序不需要太多的CPU资源。 由于String对象的标识不会更改,因此可以从应用程序中完全隐藏重复数据删除。

编译时间与运行时间

字符串池是指在编译时已知的字符串常量

如果您碰巧在运行时检索(或构造)相同的字符串一百万次,例如从文件,HTTP请求或任何其他方式读取它,字符串重复数据删除将帮助您。

只是为了添加上面的答案,在较旧的VM上,字符串池不是垃圾收集的(现在已经改变了,但不依赖于它)。 它包含在应用程序中用作常量的字符串,因此总是需要它。 如果您不断将所有字符串放在字符串池中,则可能会很快耗尽内存。 最重要的是,重复数据删除是一个相对昂贵的过程,如果你知道你只需要很长一段时间的字符串,并且你有足够的内存。

由于这些原因,字符串不会自动放入字符串池中。 您必须通过调用string.intern()显式地执行此操作。

除了这个字符串重复数据删除很有用之外,我想不出任何其他情况。

另外一个(更多)常见的场景是使用StringBuilder StringBuilder类的toString()方法中,它清楚地在内存中创建了一个新实例:

public final class StringBuilder extends AbstractStringBuilder
                                 implements java.io.Serializable, CharSequence
{
    ...

    @Override
    public String toString() {
       // Create a copy, don't share the array
       return new String(value, 0, count);
    }

    ...

}

它的线程安全版本StringBuffer

public final class StringBuffer extends AbstractStringBuilder
                                implements java.io.Serializable, CharSequence
{
   ...

   @Override
   public synchronized String toString() {
       if (toStringCache == null) {
           toStringCache = Arrays.copyOfRange(value, 0, count);
       }
       return new String(toStringCache, true);
   }

   ...
}

在严重依赖于此的应用程序中,字符串重复数据删除可能会减少内存使用量。

来自文档:

“初始化一个新创建的String对象,使其表示与参数相同的字符序列;换句话说,新创建的字符串是参数字符串的副本。除非需要原始的显式副本,否则使用此构造函数因为字符串是不可变的,所以不必要。“

所以我的感觉说,String类中的这个构造函数通常不像你上面使用的那样需要。 我想这个构造函数仅仅是为了完整性而提供的,或者如果你不想共享那个副本(现在有点不必要,请参考这里我要讨论的内容)但是其他构造函数也很有用,比如从char数组中获取一个String对象等等..

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM