我有这样的代码:
String str1 = new StringBuilder("???").append("??").toString();
System.out.println(str1.intern() == str1); //true
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2); //false
String str3 = new StringBuilder("Str").append("ing").toString();
System.out.println(str3.intern() == str3); //true
Run Code Online (Sandbox Code Playgroud)
我有结果:
String str1 = new StringBuilder("???").append("??").toString();
System.out.println(str1.intern() == str1); //true
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2); //false
String str3 = new StringBuilder("Str").append("ing").toString();
System.out.println(str3.intern() == str3); //true
Run Code Online (Sandbox Code Playgroud)
我能理解为什么line1和line3是真的,但我是关于line2的问题,为什么这是假的?
我的java是:java版"1.8.0_73"
从使用Reflector的简短外观看,它看起来像String.Substring()为每个子字符串分配内存.我是否纠正这种情况?我认为没有必要,因为字符串是不可变的.
我的基本目标是创建一个IEnumerable<string> Split(this String, Char)不分配额外内存的扩展方法.
第二个ReferenceEquals调用返回false.为什么s4中的字符串没有被中断?(我不关心StringBuilder优于字符串连接的优点.)
string s1 = "tom";
string s2 = "tom";
Console.Write(object.ReferenceEquals(s2, s1)); //true
string s3 = "tom";
string s4 = "to";
s4 += "m";
Console.Write(object.ReferenceEquals(s3, s4)); //false
Run Code Online (Sandbox Code Playgroud)
当我这样做时String.Intern(s4);,我仍然是假的.
在这里,s3和s4都被实习,但它们的引用不相等?
string s3 = "tom";
string s4 = "to";
s4 += "m";
String.Intern(s4);
Console.WriteLine(s3 == s4); //true
Console.WriteLine(object.ReferenceEquals(s3, s4)); //false
Console.WriteLine(string.IsInterned(s3) != null); //true (s3 is interned)
Console.WriteLine(string.IsInterned(s4) != null); //true (s4 is interned)
Run Code Online (Sandbox Code Playgroud) 我正在编写一个Codec来处理使用定制有线协议通过TCP发送的消息.在解码过程中,我创建了许多Strings,BigDecimals和日期.客户端 - 服务器访问模式意味着客户端发出请求然后解码数千个响应消息是常见的,这会导致大量的重复 String s,BigDecimals等.
因此我创建了一个InternPool<T>允许我实习每类对象的类.在内部,池使用a WeakHashMap<T, WeakReference<T>>.例如:
InternPool<BigDecimal> pool = new InternPool<BigDecimal>();
...
// Read BigDecimal from in buffer and then intern.
BigDecimal quantity = pool.intern(readBigDecimal(in));
Run Code Online (Sandbox Code Playgroud)
我的问题:我使用InternPool的BigDecimal,但我应该还可以考虑使用它String 来代替 String的intern()方法,我相信使用的PermGen空间?使用PermGen空间有什么好处?
由于Java的默认字符串实习已经有很多坏消息,我正在寻找替代方案.
你能建议一个API,它是Java字符串实习的一个很好的替代品吗?我的应用程序使用Java 6.我的要求主要是通过实习来避免重复的字符串.
我用户sun jdk 1.5 ThreadPoolExecutor(24,24,60,TimeUnit.SECONDS,new LinkedBlockingQueue()).soemtime我使用jdb工具查找线程池中所有线程的状态是"在监视器中等待",代码是:
String key = getKey(dt.getPrefix(), id);
synchronized (key.intern()) { ----->
Run Code Online (Sandbox Code Playgroud)
"synchronized(key.intern())"中有问题吗?
我使用jdb工具获取以下信息,24个线程的状态是"在监视器中等待",这意味着24个线程在"key.intern()"处于死锁状态.
(java.lang.Thread)0x28 pool-3-thread-2在监视器中等待
(java.lang.Thread)0x27 pool-3-thread-3在监视器中等待
(java.lang.Thread)0x1b pool-3-thread-4在监视器中等待
(java.lang.Thread)0x1a pool-3-thread-5在监视器中等待
(java.lang.Thread)0x19 pool-3-thread-6在监视器中等待
(java.lang.Thread)0x18 pool-3-thread-7在监视器中等待
(java.lang.Thread)0x17 pool-3-thread-8在监视器中等待...
所以结果是:在多线程环境中,Sting intern()方法可能会死锁,好吗?
何时应该将Strings作为对象进行比较,何时应该使用他们的equals方法?为了确保,我总是使用equals,但这似乎不是很有效.在什么情况下我可以确定string1 == string2使用安全?
谢谢!
在涉及不可变对象的某些情况下,许多不同的对象可能存在,这些对象在语义上是相同的.一个简单的例子是从文件中读取许多行文本到字符串.从程序的角度来看,两行具有相同字符序列的事实将是"巧合",但从程序员的角度来看,可能会出现大量重复.如果许多字符串实例相同,将对这些不同实例的引用更改为对单个实例的引用将节省内存,并且还将促进它们之间的比较(如果两个字符串引用指向相同的字符串,则不需要执行字符 - 通过字符比较来确定它们是相同的).
对于某些情况,系统提供的字符串实习设施可能很有用.但是,它有一些严重的限制:
如果存在true WeakDictionary<ImmutableClassType, ImmutableClassType>(对于每个元素,键和值将相同),代码可以执行以下操作:
if (theDict.TryGetValue(myString, ref internedString))
myString = internedString;
else
theDict[myString] = myString;
Run Code Online (Sandbox Code Playgroud)
不幸的是,我不知道WeakDictionary<keyType, valType>.net中的任何内置类.此外,当两个引用总是指向同一个东西时,为每个项的键和值生成弱引用似乎是浪费的.
我已经阅读了一些关于ConditionalWeakTable,这听起来像一个有趣的类,但我不认为它在这里可用,因为目标是能够采用一个实例并找到另一个在语义上等效的独立实例.
对于类的实例具有明确定义的生命周期的情况,使用常规Dictionary来合并相同的实例可能是合理的.然而,在许多情况下,可能很难知道何时Dictionary应放弃这样的物品或清除其中的物品.WeakReference基于A 的实习收集将避免此类问题.这样的事情是存在的,还是可以很容易实现的?
附录
正如svick所指出的那样,Dictionary<WeakReference, WeakReference>问题会有些问题,因为没有切实可行的方法来定义IEqualityComparer哪一个会实时WeakReference返回GetHashCode其目标的值,并且有一个死人继续返回该值.可以定义一个结构,它将包含一个整数target-hashcode值(在构造函数中设置),并且它自己GetHashCode将返回该整数.稍微改进可能是使用a ConditionalWeakTable将目标链接WeakReference到可终结对象,该目标可用于将表项排入队列以进行删除.
我不确定尝试急切地清理字典与采取更为被动的方法之间的适当平衡是什么(例如,如果自上次扫描以来至少有一个GC,则在添加项目时执行扫描,以及数字自上次扫描以来添加的项目超过了幸存的项目数量).扫描字典中的所有内容并不是免费的,但ConditionalWeakTable可能也不会是免费的.
PPS
我想到的另一个概念,但我认为它可能不如弱实用方法那样有用,就是让一个逻辑不可变类型保存一个可变的"timestamp"值,并且有一个接受的比较方法它的论点ref.如果发现两个不同的实例相等,则将检查它们的时间戳值.如果两者都为零,则将从全局计数器(-1,-2,-3等)中为它们分配连续的负数.具有(或被分配)较低时间戳值的参数然后将被另一个替换.
使用这种方法,如果许多对象实例被重复地相互比较,则许多引用将被替换为对"较旧"实例的引用.根据使用模式,这可能导致大多数相同的对象实例被合并而不使用任何类型的实习字典.但是,对嵌套对象应用这种方法需要"不可变"对象允许嵌套对象引用变异以指向其他所谓相同的嵌套对象.如果"假设相同"的对象总是如此,那么这应该没问题,但如果不是这样,可能会导致相当奇怪的错误行为.
在探索了java的字符串内部结构后,我对所谓的"烫发空间"感到困惑.我最初的理解是它保留了String 文字以及类元数据,如本问题所述.
我还阅读了有关该String.intern()方法的内容,并将其String放入String Pool中,返回对它的唯一实例的引用.我的理解是,这是与JVM的perm空间中存在的字符串文字相同的字符串池.对我来说,"烫发空间"可以修改是不可能的(毕竟它是永久性的,是吗?).但后来我发现这个问题,EJP对接受的答案的最高投票评论解释了这一点
现在,实习生的字符串已经可以用GC了.
暗示GC在perm空间上运行,这似乎不是永久性的.这如何调和?GC是否检查了烫发空间中的所有内容?GC是否检查字符串池中的所有内容,包括源中的字符串文字?内联字符串是否有第二个字符串池?GC是否只知道在收集时查看实习生的字符串?或者这个评论是错误的并且实际上是一个字符串阻止它成为GC'd(我希望不是这种情况)?