Sebagai pengembang perangkat lunak, kami selalu ingin perangkat lunak yang kami tulis berjalan cepat. Dengan menggunakan algoritma yang optimal, memparalelkan, menerapkan berbagai teknik pengoptimalan - kami akan menggunakan semua cara yang kami ketahui untuk meningkatkan kinerja perangkat lunak. Salah satu teknik optimasi ini adalah apa yang disebut dengan string interning. Ini memungkinkan Anda mengurangi jumlah memori yang dikonsumsi oleh proses, dan juga secara signifikan mengurangi waktu yang dihabiskan untuk membandingkan string. Namun, seperti di tempat lain dalam hidup, perlu untuk mengamati ukuran - Anda tidak boleh menggunakan penahanan di setiap langkah. Sisa artikel ini akan menunjukkan kepada Anda bagaimana Anda dapat membakar diri Anda sendiri dan membuat kemacetan yang tidak terlihat untuk aplikasi Anda dalam bentuk metode 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#.