在我发现常见/最新的Javascript实现正在使用String Interning进行性能提升(常见的JavaScript实现是否使用字符串实习?)时,我认为===字符串将获得恒定的O(1)时间.所以我对这个问题给出了错误的答案:
因为根据该问题的OP,它是O(N),所以将字符串输入加倍是等于需要的时间的两倍.他没有提供任何jsPerf,所以需要更多的调查,
所以我使用字符串实习的方案是:
var str1 = "stringwithmillionchars"; //stored in address 51242
var str2 = "stringwithmillionchars"; //stored in address 12313
"stringwithmillionchars"将被存储一次,比如在地址201012的内存中,并且str1和str2都将"指向"该地址201012.然后可以通过某种散列来确定该地址以映射到存储器中的特定位置.
这样做的时候
"stringwithmillionchars" === "stringwithmillionchars"
看起来像
getContentOfAddress(51242)===getContentOfAddress(12313)
要么 201012 === 201012
需要O(1)/恒定时间
JSPerfs /性能更新:
即使字符串长16倍,JSPerf似乎也显示常量时间?请看一看:
http://jsperf.com/eqaulity-is-constant-time
可能上面的字符串太小:这可能显示线性时间(感谢sergioFC)字符串是用循环构建的.我试过没有功能 - 仍然线性时间/我改变了一点http://jsfiddle.net/f8yf3c7d/3/.
根据https://www.dropbox.com/s/8ty3hev1b109qjj/compare.html?dl=0(sergioFC制作的 12MB文件)当你有一个字符串并且你已经在引号中分配了值,无论t1有多大和t2是(例如5930496个字符),它是0-1ms /即时时间.
看来,当你使用for循环或函数构建一个字符串时,字符串不会被实现.因此只有当您直接为带有引号的字符串分配时,才会发生实习var str = "test";
javascript string performance time-complexity string-interning
在下面的例子中,我在构造函数中实现字符串,这很好.但是当我从二进制格式化程序反序列化对象时,我不认为该字符串将被实现,因为应该调用构造函数.我应该如何确保_name字符串被实现?......还是会被拘禁好吗?
编辑:所以它似乎工作(正确实习字符串)而不处理OnDeserializedAttribute.它是如何做到的?
我正在使用内存分析器,无论有没有下面的方法,它仍然可以实现字符串?魔法?: - /
[OnDeserializedAttribute]
private void OnDeserialized(StreamingContext context)
{
_name = string.Intern(_name);
}
Run Code Online (Sandbox Code Playgroud)
谢谢
[Serializable]
class City
{
private readonly string _name;
public City(string t)
{
_name = string.Intern(t);
}
public string Name
{
get { return _name; }
}
public override string ToString()
{
return _name;
}
}
Run Code Online (Sandbox Code Playgroud) 我不明白:
MSDN说
http://msdn.microsoft.com/en-us/library/system.string.intern.aspx
因此,具有特定值的文字字符串实例仅在系统中存在一次.
例如,如果将相同的文字字符串分配给多个变量,则运行时将从实习池中检索对文字字符串的相同引用,并将其分配给每个变量.
这种行为是默认的(没有实习生)吗?或者使用Intern方法?
如果是默认值,为什么我要使用实习生?(实例将一次......)?
如果它是NOT默认值:如果我写了1000次这一行:
Console.WriteLine( "LALALA");
1)我会在记忆中得到1000次"lalala"吗?(不使用实习生...)
2)将"lalala"最终Gc'ed?
3)"lalala"是否已被实习?如果确实如此,为什么我需要从池中"获取"它,而不是再次写"lalala"?
我有点困惑.
我有一个网络客户端来处理来自服务器的数据.
数据作为一系列消息发送,这些消息本身是键/值集合,在概念上类似于HTTP头(除了没有"消息体"),这里是一个典型的单向消息(行分隔\r\n):
Response: OK
Channel: 123
Status: OK
Message: Spectrum is green
Author: Gerry Anderson
Foo123: Blargh
Run Code Online (Sandbox Code Playgroud)
我的协议客户端通过NetworkStream使用a来逐个字符地读取StreamReader,while( (nc = rdr.Read()) != -1 )并使用状态机解析器和StringBuilder实例来填充Dictionary<String,String>实例.然后将这些Dictionary实例保存到内存结构中以进行进一步处理,它们通常具有大约10分钟的有用寿命.
我的客户端每小时收到数千条这样的消息,而且客户端进程持久 - 这是一个问题,因为我的客户端进程通常会从这些String实例中消耗超过2GB的内存- 我使用windbg查看所有内存的运行情况.这是一个问题,因为代码在只有3.5GB内存的Azure VM上运行.我认为我的程序最多只能消耗超过几百MB的RAM.通常我会坐在虚拟机上观察我的进程随着时间的推移消耗的内存消耗,它会稳定地增长到大约2GB,然后随着GC的收集运行突然降到大约100MB,然后它会再次增长.GC运行之间的时间可能不同,根本没有可预测性.
因为这么多的这些字符串是相同的(如键Response,Status等)以及像已知值OK和Fail我可以使用字符串实习,以减少使用量,如下所示:
// In the state-machine parser after having read a Key name:
String key = stringBuilder.ToString();
key = String.Intern( key );
// etc... after reading value
messageDictionary.Add( key, value …Run Code Online (Sandbox Code Playgroud) 我正在构建一个Python实用程序,它将涉及将整数映射到字符串,其中许多整数可能映射到相同的字符串.根据我的理解,默认情况下Python实习短字符串和大多数硬编码字符串,因此通过在表中保留字符串的"规范"版本来节省内存开销.我认为我可以通过实习字符串值从中受益,即使字符串实习更多地用于密钥散列优化.我写了一个快速测试,它检查长字符串的字符串相等性,首先只存储列表中的字符串,然后将字符串存储在字典中作为值.这种行为对我来说意外:
import sys
top = 10000
non1 = []
non2 = []
for i in range(top):
s1 = '{:010d}'.format(i)
s2 = '{:010d}'.format(i)
non1.append(s1)
non2.append(s2)
same = True
for i in range(top):
same = same and (non1[i] is non2[i])
print("non: ", same) # prints False
del non1[:]
del non2[:]
with1 = []
with2 = []
for i in range(top):
s1 = sys.intern('{:010d}'.format(i))
s2 = sys.intern('{:010d}'.format(i))
with1.append(s1)
with2.append(s2)
same = True
for i in range(top):
same = same and (with1[i] is with2[i]) …Run Code Online (Sandbox Code Playgroud) 我们在项目中使用hibernate验证器和动态类加载(通过加载类进入单独的类加载器).在我们意识到不需要该类之后,我们删除对类和类加载器的所有引用,然后GC收集它.
我们得到的结果:应用程序启动后的一段时间,java反射停止工作.
java.lang.reflect.UndeclaredThrowableException: null
at com.sun.proxy.$Proxy253.equals(Unknown Source)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager$CacheKey.equals(ConstraintValidatorManager.java:287)
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:940)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.getInitializedValidator(ConstraintValidatorManager.java:104)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorNoUnwrapping(ConstraintTree.java:301)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorInstanceForAutomaticUnwrapping(ConstraintTree.java:242)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getInitializedConstraintValidator(ConstraintTree.java:163)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:116)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateComposingConstraints(ConstraintTree.java:396)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:98)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:87)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:73)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:616)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:581)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:527)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:495)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:460)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:410)
at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:207)
at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:281)
... Many spring filters calls ...
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:122)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at *someAwesomePackage*.microservice.rest.spring.webapp.CabinetRequestFilter.doFilterInternal(CabinetRequestFilter.java:98)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at …Run Code Online (Sandbox Code Playgroud) java reflection dynamic-class-loaders hibernate-validator string-interning
下面是String.intern()方法的Javadoc注释:
*返回字符串对象的规范表示.
最初为空的字符串池由String类私有维护.
调用实习方法时,如果池已经包含等于此字符串对象的字符串(由equals(Object)方法确定),则返回池中的字符串.否则,将此String对象添加到池中,并返回对此String对象的引用.
因此,对于任何两个字符串s和t,当且仅当s.equals(t)为真时,s.intern()== t.intern()才为真.
所有文字字符串和字符串值常量表达式都是实体.字符串文字在The Java™Language Specification的3.10.5节中定义."
但我觉得有些事情从jdk-8u102开始改变了.
检查以下示例:
public class Test1 {
public static void main(String[] args) {
String s1 = new String(new char[]{'J', 'a', 'v', 'a'});
String s2 = s1.intern();
System.out.println(s1 == s2);
}
}
Run Code Online (Sandbox Code Playgroud)
如果在JDK 7u80(JDK 7的最后稳定版本)和JDK 8到8u101上运行以上程序,则输出为:
true
但是如果你在JDK 8u102以及JDK 9和JDK 10中运行以上程序,则输出为:
false
为什么intern()方法开始表现不同JDK 8u102以后?
我检查了发行说明和Javadoc注释,但在JDK 8u102中找不到与intern()方法相关的更改.
我查了博客和其他网站,但没有运气.
但是当我尝试使用其他字符串时,输出没有变化:
public class Test2 {
public static void main(String[] args) {
String s3 = new String(new char[]{'U', 'd', 'a', 'y', 'a', 'n'});
String s4 = …Run Code Online (Sandbox Code Playgroud) 这里有一个简单的问题:
我发现对于某些对象,调用str实际上可以创建新的对象引用
>>> a = 1
>>> str(a) is str(a)
False
Run Code Online (Sandbox Code Playgroud)
然而,我注意到这对于字符串来说并非如此(这看起来很直观)。该str方法是否始终充当对象的标识函数str?或者,由于字符串驻留优化,该属性似乎是正确的,并且实际上可能不会返回相同的引用?
>>> a = "1"
>>> a is str(a)
True
>>> str(a) is str(a)
True
Run Code Online (Sandbox Code Playgroud)
这是全局规则/语言规范规则,还是依赖于解释器?
FWIW 我问这个问题是因为在一些地方我保护了一些方法来确保str使用实例。我想知道我是否通过str在已经是 type 的输入周围添加冗余调用来创建垃圾str。例如
def safeguard_foo(val):
foo(str(val))
Run Code Online (Sandbox Code Playgroud)
另一种选择是以更详细的方式进行保护(值得注意的是,无论如何,这种方法大约快 25%,因此在性能方面,即使在考虑垃圾创建问题之前,它也胜出)。例如
def safeguard_foo(val):
if not isinstance(val, str):
val = str(val)
foo(val)
Run Code Online (Sandbox Code Playgroud) 考虑以下C#代码:
var a = "123";
var b = 123.ToString();
Console.WriteLine(a==b);
Console.WriteLine(ReferenceEquals(a, b));
Console.WriteLine("a interned? " + string.IsInterned(a));
Console.WriteLine("b interned? " + string.IsInterned(b));
Console.WriteLine(
ReferenceEquals(
string.IsInterned(a),
string.IsInterned(b)
)
);
Run Code Online (Sandbox Code Playgroud)
这个输出
True
False
a interned? 123
b interned? 123
True
Run Code Online (Sandbox Code Playgroud)
这个一切都使得除为什么感觉ReferenceEquals(a,b)返回false考虑a得到了实习,然后b会提到a,由指示string.IsInterned检查。
a = 'This is a very long string. This is a very long string. No?'
b = 'This is a very long string. This is a very long string. No?'
print(id(a), id(b))
print(a is b)
Run Code Online (Sandbox Code Playgroud)
在我的电脑上,结果是:
4467772080 4467772080
True
Run Code Online (Sandbox Code Playgroud)
据我所知,Python 只缓存短字符串。但是为什么这么长的字符串,它仍然只保留一个副本?其实我把它改成了一个很长的字符串(甚至比1024还长),a和b仍然指向同一个字符串对象。请纠正我哪里错了?
string-interning ×10
string ×6
c# ×4
python ×3
.net ×2
java ×2
dictionary ×1
javascript ×1
performance ×1
python-3.x ×1
reflection ×1
string-pool ×1