Como desenvolvedores de software, sempre queremos que o software que escrevemos seja executado rapidamente. Usando o algoritmo ótimo, paralelizando, aplicando várias técnicas de otimização - vamos recorrer a todos os meios que conhecemos para melhorar o desempenho do software. Uma dessas técnicas de otimização é o chamado estágio de string. Ele permite que você reduza a quantidade de memória consumida pelo processo e também reduz significativamente o tempo gasto na comparação de strings. Porém, como em outras partes da vida, é preciso observar a medida - não se deve usar a internação em todas as etapas. O restante deste artigo mostrará como você pode se queimar e criar um gargalo não óbvio para seu aplicativo na forma do método String.Intern.
, , , C# . , – , , String, .
, , : , . . 100 %, . , 1 , , 4,7 ( 100 ). , , , , . , .
, String . -, ( String Pool). , . , , , . , , String. String, . , ( ). : String.Intern String.IsInterned.
, , String. , . IsInterned . , null ( ).
, , Intern. , , . , , , . , . , , .
. String.Equals:
public bool Equals(String value)
{
if (this == null)
throw new NullReferenceException();
if (value == null)
return false;
if (Object.ReferenceEquals(this, value))
return true;
if (this.Length != value.Length)
return false;
return EqualsHelper(this, value);
}
EqualsHelper, , Object.ReferenceEquals . , Object.ReferenceEquals true ( ). , , EqualsHelper . Equals , , false ReferenceEquals .
, , Object.ReferenceEquals. . - , – . ReferenceEquals , .
, . , . .
, , , .
,
bug tracker' - , : ++ . , PVS-Studio . , , IncrediBuild. IncrediBuild , , . , , , , ( ), . .
, , PVS-Studio , IncrediBuild, , . – . , .
open source Unreal Tournament. IncrediBuild . 145 .
Unreal Tournament PVS-Studio, . CLMonitor.exe , Unreal Tournament Visual Studio. , , CLMonitor.exe, . PVS-Studio ThreadCount, CLMonitor.exe PVS-Studio.exe, ++ . PVS-Studio.exe , CLMonitor.exe.
: ThreadCount PVS-Studio, (145), , , 145 PVS-Studio.exe . IncrediBuild Build Monitor, , . - :
, : , , IncrediBuild . ...
,
, PVS-Studio.exe Build Monitor. IncrediBuild IncrediBuild. , , , : 182 8 50 IncrediBuild 145 . , 18 , 3,5 . Build Monitor. , :
, PVS-Studio.exe , - PVS-Studio.exe. . . . , , – IncrediBuild. - .
. , , . , CLMonitor.exe , . "" , CLMonitor.exe Visual Studio . Threads, 145 . , , :
....
return String.Intern(settings == null ? path
: settings
.TransformToRelative(path.Replace("/", "\\"),
solutionDirectory));
....
analyzedSourceFiles.Add( String.Intern(settings
.TransformPathToRelative(analyzedSourceFilePath,
solutionDirectory))
);
....
? String.Intern. . , , CLMonitor.exe , PVS-Studio.exe. ErrorInfo, . , . , , ErrorInfo . .
, . , . - 145 String.Intern, LimitedConcurrencyLevelTaskScheduler CLMonitor.exe , PVS-Studio.exe, IncrediBuild . , , – PVS-Studio.exe ErrorInfo . , PVS-Studio.exe . , 145 .
ThreadCount , , String.Intern.
, CLMonitor.exe. : , PVS-Studio.exe ( , ).
, . Build Monitor - PVS-Studio.exe. 50 26, . , IncrediBuild 145 , 7 . , 3,5 .
String.Intern – , CoreCLR
, String.Intern, , - lock'. , String.Intern - , , , . , String.Intern reference source. , – Thread.GetDomain().GetOrInternString(str). , :
internal extern String GetOrInternString(String str);
. - . ? - CLR, .NET. , CoreCLR. , GetOrInternString :
STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString)
GetInternedString. , :
....
if (m_StringToEntryHashTable->GetValue(&StringData, &Data, dwHash))
{
STRINGREF *pStrObj = NULL;
pStrObj = ((StringLiteralEntry*)Data)->GetStringObject();
_ASSERTE(!bAddIfNotFound || pStrObj);
return pStrObj;
}
else
{
CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()
->m_HashTableCrstGlobal));
....
// Make sure some other thread has not already added it.
if (!m_StringToEntryHashTable->GetValue(&StringData, &Data))
{
// Insert the handle to the string into the hash table.
m_StringToEntryHashTable->InsertValue(&StringData, (LPVOID)pEntry, FALSE);
}
....
}
....
else , , String ( GetValue) , false. , else. CrstHolder gch. CrstHolder :
inline CrstHolder(CrstBase * pCrst)
: m_pCrst(pCrst)
{
WRAPPER_NO_CONTRACT;
AcquireLock(pCrst);
}
AcquireLock. . AcquireLock:
DEBUG_NOINLINE static void AcquireLock(CrstBase *c)
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
c->Enter();
}
, , – Enter. , , , , : "Acquire the lock". CoreCLR . , , , , , . CrstHolder, , m_StringToEntryHashTable->InsertValue.
, else. gch , ReleaseLock:
inline ~CrstHolder()
{
WRAPPER_NO_CONTRACT;
ReleaseLock(m_pCrst);
}
, . , 145 ( IncrediBuild), , , 144 , . Build Monitor.
, , . " ", . , , .
.
, : Ilya Gainulin. Pitfalls in String Pool, or Another Reason to Think Twice Before Interning Instances of String Class in C#.