බැහැර කිරීමේ කාරණය වන්නේ කළමනාකරණය නොකළ සම්පත් නිදහස් කිරීමයි. එය යම් අවස්ථාවක දී කළ යුතුය, එසේ නොමැති නම් ඒවා කිසි විටෙකත් පිරිසිදු නොකෙරේ. කුණු එකතු දන්නේ නැහැ කොහොමද කැඳවීමට DeleteHandle()
වර්ගයේ විචල්ය මත IntPtr
, එය දන්නේ නැහැ යන්න එය ඇමතුමක් කිරීමට අවශ්ය නැද්ද DeleteHandle()
.
සටහන : කළමනාකරණය නොකළ සම්පතක් යනු කුමක්ද? ඔබ එය මයික්රොසොෆ්ට් .නෙට් රාමුව තුළ සොයා ගත්තේ නම්: එය කළමනාකරණය කර ඇත. ඔබ එම්එස්ඩීඑන් වටා එබී බැලුවහොත් එය පාලනය කළ නොහැක. .NET රාමුව තුළ ඔබට ලබා ගත හැකි සෑම දෙයක්ම ලස්සන සුවපහසු ලෝකයෙන් පිටතට ගෙන ඒමට ඔබ P / Invoke ඇමතුම් භාවිතා කර ඇති ඕනෑම දෙයක් කළමනාකරණය කර නැත - එය පිරිසිදු කිරීමේ වගකීම දැන් ඔබ සතුය.
කළමනාකරණය නොකළ සම්පත් පිරිසිදු කිරීම සඳහා ඔබ විසින් නිර්මාණය කරන ලද වස්තුවට බාහිර ලෝකයට ඇමතිය හැකි යම් ක්රමවේදයක් හෙළි කළ යුතුය. ඔබ කැමති ඕනෑම දෙයක් මෙම ක්රමය නම් කළ හැකිය:
public void Cleanup()
හෝ
public void Shutdown()
නමුත් ඒ වෙනුවට මෙම ක්රමය සඳහා ප්රමිතිගත නමක් ඇත:
public void Dispose()
අතුරු මුහුණතක් පවා නිර්මාණය IDisposable
කර ඇත, එයට ඇත්තේ එක් ක්රමයක් පමණි:
public interface IDisposable
{
void Dispose()
}
එබැවින් ඔබ ඔබේ වස්තුව IDisposable
අතුරු මුහුණත නිරාවරණය කිරීමට සලස්වන අතර , එමඟින් ඔබ කළමනාකරණය නොකරන ලද සම්පත් පිරිසිදු කිරීම සඳහා එම තනි ක්රමය ලියා ඇති බවට පොරොන්දු වේ:
public void Dispose()
{
Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
}
ඔබ ඉවරයි. ඔබට වඩා හොඳින් කළ හැකි හැර.
ඔබේ වස්තුව යම් ආකාරයක රාමු බෆරයක් ලෙස 250MB System.Drawing.Bitmap (එනම් .NET කළමනාකරණය කළ බිට්මැප් පන්තිය) වෙන් කර ඇත්නම් කුමක් කළ යුතුද? නිසැකවම, මෙය කළමනාකරණය කළ .NET වස්තුවක් වන අතර කසළ එකතු කරන්නා එය නිදහස් කරයි. නමුත් ඔබට ඇත්ත වශයෙන්ම අවශ්ය වන්නේ මෙගාබයිට් 250 ක මතකයක් එහි හිඳගෙන සිටීමයි - කසළ එකතු කරන්නා අවසානයේ පැමිණ එය නිදහස් කරන තෙක් බලා සිටිනවාද? මොන තියෙනවා නම් විවෘත දත්තගබඩා සම්බන්ධතා ? නිසැකවම අපට එම සම්බන්ධතාවය විවෘතව තබා ගැනීමට අවශ්ය නැත, GC වස්තුව අවසන් වන තෙක් බලා සිටී.
පරිශීලකයා ඇමතුවේ නම් Dispose()
(එයින් අදහස් කරන්නේ ඔවුන් තවදුරටත් වස්තුව භාවිතා කිරීමට අදහස් නොකරන බවයි) එම නාස්තිකාර බිට්මැප් සහ දත්ත සමුදා සම්බන්ධතා ඉවත් නොකරන්නේ ඇයි?
දැන් අපි:
- කළමනාකරණය නොකළ සම්පත් ඉවත් කරන්න (අපට කළ යුතු නිසා), සහ
- කළමනාකරණ සම්පත් ඉවත් කරන්න (අපට උදව් කිරීමට අවශ්ය නිසා)
එබැවින් Dispose()
එම කළමනාකරණය කළ වස්තූන් ඉවත් කිරීම සඳහා අපගේ ක්රමය යාවත්කාලීන කරමු :
public void Dispose()
{
//Free unmanaged resources
Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
//Free managed resources too
if (this.databaseConnection != null)
{
this.databaseConnection.Dispose();
this.databaseConnection = null;
}
if (this.frameBufferImage != null)
{
this.frameBufferImage.Dispose();
this.frameBufferImage = null;
}
}
සියලු යහපත් ඔබ වඩා හොඳින් කළ හැකි හැර !
ඔබේ වස්තුව ඇමතීමට පුද්ගලයාට අමතක වුවහොත් කුමක් කළ Dispose()
යුතුද? එවිට ඔවුන් කළමනාකරණය නොකළ සම්පත් කිහිපයක් කාන්දු වනු ඇත !
සටහන: ඒවා කළමණාකරන සම්පත් කාන්දු නොකරනු ඇත , මන්ද අවසානයේදී කසළ එකතු කරන්නා පසුබිම් නූල් මත ධාවනය වන අතර භාවිතයට නොගත් ඕනෑම වස්තුවක් සමඟ සම්බන්ධිත මතකය නිදහස් කරයි. මෙයට ඔබේ වස්තුව සහ ඔබ භාවිතා කරන ඕනෑම කළමනාකරණ වස්තු ඇතුළත් වේ (උදා: Bitmap
සහ. DbConnection
).
පුද්ගලයාට ඇමතීමට අමතක වූවා නම් Dispose()
, අපට තවමත් ඔවුන්ගේ බේකන් ඉතිරි කළ හැකිය ! ඔවුන් සඳහා එය කැඳවීමට අපට තවමත් ක්රමයක් තිබේ : කසළ එකතු කරන්නා අවසානයේ අපගේ වස්තුව නිදහස් කිරීමට (එනම් අවසන් කිරීමට) ගිය විට.
සටහන: කසළ එකතු කරන්නා අවසානයේ කළමනාකරණය කරන ලද සියලුම වස්තු නිදහස් කරයි. එය සිදු වූ විට, එය Finalize
වස්තුව මත ඇති ක්රමය අමතයි . ඔබේ බැහැර කිරීමේ ක්රමය ගැන GC දන්නේ නැත . කළමනාකරණය නොකළ දේවල් ඉවත් කිරීමට අවශ්ය විට අප අමතන ක්රමයක් සඳහා අප තෝරාගත් නමක් පමණි.
කසළ එකතු කරන්නා විසින් අපගේ වස්තුව විනාශ කිරීම එම කරදරකාරී කළමනාකරණය නොකළ සම්පත් නිදහස් කිරීමට සුදුසුම කාලයයි. අපි මෙය කරන්නේ Finalize()
ක්රමවේදය ඉක්මවා යාමෙනි .
සටහන: C # හි, ඔබ පැහැදිලිවම Finalize()
ක්රමය ඉක්මවා යන්නේ නැත . ඔබ ක්රමයක් ලියන්න වගේ එය C ++ destructor , සහ සම්පාදක බව ඔබේ ක්රියාත්මක කිරීම සඳහා අවශ්ය කරන්නේ Finalize()
ක්රමය:
~MyObject()
{
//we're being finalized (i.e. destroyed), call Dispose in case the user forgot to
Dispose(); //<--Warning: subtle bug! Keep reading!
}
නමුත් එම කේතයේ දෝෂයක් තිබේ. කසළ එකතු කරන්නා පසුබිම් නූල් මත ධාවනය වන බව ඔබට පෙනේ ; වස්තූන් දෙකක් විනාශ වන අනුපිළිවෙල ඔබ දන්නේ නැත. ඔබගේ Dispose()
කේතයේ, ඔබ ඉවත් කිරීමට උත්සාහ කරන කළමනාකරණ වස්තුව (ඔබට උදව් කිරීමට අවශ්ය නිසා) තවදුරටත් එහි නොමැති බව සම්පුර්ණයෙන්ම විය හැකිය :
public void Dispose()
{
//Free unmanaged resources
Win32.DestroyHandle(this.gdiCursorBitmapStreamFileHandle);
//Free managed resources too
if (this.databaseConnection != null)
{
this.databaseConnection.Dispose(); //<-- crash, GC already destroyed it
this.databaseConnection = null;
}
if (this.frameBufferImage != null)
{
this.frameBufferImage.Dispose(); //<-- crash, GC already destroyed it
this.frameBufferImage = null;
}
}
එබැවින් ඔබට අවශ්ය වන්නේ කළමනාකරණය නොකළ සම්පත් නිදහස් කරන අතරම එය කළමනාකරණය කළ සම්පත් කිසිවක් ස්පර්ශ නොකළ යුතු බව Finalize()
පැවසීමට මාර්ගයකි (ඒවා තවදුරටත් එහි නොතිබිය හැකි නිසා ).Dispose()
මෙය සිදු කිරීම සඳහා සම්මත රටාව තිබිය යුතු Finalize()
අතර Dispose()
දෙදෙනාම තුන්වන (!) ක්රමයක් අමතන්න ; එහිදී ඔබ බූලියන් කියමින් එය අමතන්නේ නම් Dispose()
(ඊට වෙනස්ව Finalize()
), එයින් අදහස් කරන්නේ කළමනාකරණය කළ සම්පත් නිදහස් කිරීම ආරක්ෂිත බවයි.
මෙම අභ්යන්තර ක්රමයට “CoreDispose” හෝ “MyInternalDispose” වැනි අත්තනෝමතික නමක් ලබා දිය හැකි නමුත් එය හැඳින්වීම සම්ප්රදායයි Dispose(Boolean)
:
protected void Dispose(Boolean disposing)
නමුත් වඩාත් ප්රයෝජනවත් පරාමිති නාමයක් විය හැකිය:
protected void Dispose(Boolean itIsSafeToAlsoFreeManagedObjects)
{
//Free unmanaged resources
Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
//Free managed resources too, but only if I'm being called from Dispose
//(If I'm being called from Finalize then the objects might not exist
//anymore
if (itIsSafeToAlsoFreeManagedObjects)
{
if (this.databaseConnection != null)
{
this.databaseConnection.Dispose();
this.databaseConnection = null;
}
if (this.frameBufferImage != null)
{
this.frameBufferImage.Dispose();
this.frameBufferImage = null;
}
}
}
ඔබ IDisposable.Dispose()
ක්රමවේදය ක්රියාත්මක කිරීම වෙනස් කරන්නේ:
public void Dispose()
{
Dispose(true); //I am calling you from Dispose, it's safe
}
සහ ඔබේ අවසන් කරන්නා:
~MyObject()
{
Dispose(false); //I am *not* calling you from Dispose, it's *not* safe
}
සටහන : ඔබේ වස්තුව ක්රියාත්මක වන්නේ වස්තුවකින් නම් Dispose
, ඔබ ඒවා ඉක්මවා යන විට ඒවායේ පදනම බැහැර කිරීමේ ක්රමය අමතන්න අමතක නොකරන්න .
public override void Dispose()
{
try
{
Dispose(true); //true: safe to free managed resources
}
finally
{
base.Dispose();
}
}
සියලු යහපත් ඔබ වඩා හොඳින් කළ හැකි හැර !
පරිශීලකයා Dispose()
ඔබේ වස්තුව අමතන්නේ නම් , එවිට සියල්ල පිරිසිදු කර ඇත. පසුව, කසළ එකතු කරන්නා පැමිණ අවසන් කරන්නැයි ඇමතූ විට, එය Dispose
නැවත අමතනු ඇත.
මෙය නාස්තියක් පමණක් නොව, ඔබේ වස්තුවට ඔබ අවසන් ඇමතුමේ සිට දැනටමත් බැහැර කර ඇති වස්තූන් පිළිබඳ අපැහැදිලි යොමු කිරීම් තිබේ නම් Dispose()
, ඔබ ඒවා නැවත බැහැර කිරීමට උත්සාහ කරනු ඇත!
මගේ කේතයෙන් ඔබ දකිනු ඇත, මා විසින් බැහැර කරන ලද වස්තූන් පිළිබඳ යොමු කිරීම් ඉවත් කිරීමට මම ප්රවේශම් වූ බැවින් මම Dispose
කුණු වස්තු යොමු කිරීමක් ඇමතීමට උත්සාහ නොකරමි . නමුත් එය සියුම් දෝෂයක් ඇතුළට යාම නතර කළේ නැත.
පරිශීලකයා ඇමතූ විට Dispose()
: CursorFileBitmapIconServiceHandle හසුරුව විනාශ වේ. පසුව කසළ එකතු කරන්නා ධාවනය වන විට, එය නැවත එම හසුරුව විනාශ කිරීමට උත්සාහ කරනු ඇත.
protected void Dispose(Boolean iAmBeingCalledFromDisposeAndNotFinalize)
{
//Free unmanaged resources
Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle); //<--double destroy
...
}
ඔබ මෙය නිවැරදි කරන ආකාරය කුණු එකතු කරන්නාට පවසන්න, එය වස්තුව අවසන් කිරීමට කරදර විය යුතු නැත - එහි සම්පත් දැනටමත් පිරිසිදු කර ඇති අතර තවත් වැඩක් අවශ්ය නොවේ. ඔබට ඇමතීම මගින් මේ GC.SuppressFinalize()
තුළ Dispose()
ක්රමය:
public void Dispose()
{
Dispose(true); //I am calling you from Dispose, it's safe
GC.SuppressFinalize(this); //Hey, GC: don't bother calling finalize later
}
දැන් පරිශීලකයා ඇමතූ විට Dispose()
, අපට ඇත්තේ:
- කළමනාකරණය නොකළ සම්පත් නිදහස්
- කළමනාකරණ සම්පත් නිදහස්
අවසන් මහා තරගය පවත්වාගෙන යාමේ කිසිදු තේරුමක් නැත - සෑම දෙයක්ම බලා ගනී.
කළමනාකරණය නොකළ සම්පත් පිරිසිදු කිරීම සඳහා මට අවසන් කිරීම භාවිතා කළ නොහැකිද?
සඳහා වන ලියකියවිලි Object.Finalize
මෙසේ කියයි:
වස්තුව විනාශ වීමට පෙර වත්මන් වස්තුව සතුව ඇති කළමනාකරණය නොකළ සම්පත් මත පිරිසිදු කිරීමේ මෙහෙයුම් සිදු කිරීම සඳහා අවසාන ක්රමය භාවිතා කරයි.
එම්එස්ඩීඑන් ලියකියවිලි ද මෙසේ කියයි IDisposable.Dispose
:
කළමනාකරණය නොකළ සම්පත් නිදහස් කිරීම, මුදා හැරීම හෝ නැවත සැකසීම හා සම්බන්ධ යෙදුම්-නිර්වචනය කළ කාර්යයන් ඉටු කරයි.
ඉතින් එය කුමක්ද? කළමනාකරණය නොකළ සම්පත් පිරිසිදු කිරීමට මට ඇති ස්ථානය කුමක්ද? පිළිතුර:
එය ඔබේ තේරීමයි! නමුත් තෝරන්න Dispose
.
ඔබට කළමණාකරනය නොකළ පිරිසිදු කිරීම අවසාන කොටසේ තැබිය හැකිය.
~MyObject()
{
//Free unmanaged resources
Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
//A C# destructor automatically calls the destructor of its base class.
}
එහි ඇති ගැටළුව නම් කසළ එකතු කරන්නා ඔබේ වස්තුව අවසන් කරන්නේ කවදාද යන්න ගැන ඔබට කිසිම අදහසක් නැත. ඔබේ කළමනාකරණය නොකළ, අනවශ්ය, භාවිතයට නොගත් දේශීය සම්පත් කසළ එකතු කරන්නා අවසානයේදී ක්රියාත්මක වන තුරු රැඳී සිටියි. එවිට එය ඔබගේ අවසන් කිරීමේ ක්රමය අමතනු ඇත; කළමනාකරණය නොකළ සම්පත් පිරිසිදු කිරීම. Object.Finalize හි ප්රලේඛනය මෙය පෙන්වා දෙයි:
අවසන් කරන්නා ක්රියාත්මක කරන නිශ්චිත වේලාව නිර්වචනය කර නැත. ඔබේ පන්තියේ අවස්ථා සඳහා නිශ්චිතවම සම්පත් මුදා හැරීම සහතික කිරීම සඳහා, වසා දැමීමේ ක්රමයක් IDisposable.Dispose
ක්රියාත්මක කිරීම හෝ ක්රියාත්මක කිරීම සපයන්න .
Dispose
කළමනාකරණය නොකළ සම්පත් පිරිසිදු කිරීම සඳහා භාවිතා කිරීමේ ගුණාංගය මෙයයි ; කළමනාකරණය නොකළ සම්පත් පිරිසිදු කළ විට ඔබ දැන හඳුනා ගැනීම සහ පාලනය කිරීම. ඔවුන්ගේ විනාශය "නිර්ණායක" ය .
ඔබේ මුල් ප්රශ්නයට පිළිතුරු සැපයීම සඳහා: GC එය කිරීමට තීරණය කළ කාලයට වඩා දැන් මතකය නිදහස් නොකරන්නේ ඇයි? බව මට මුහුණේ පිළිගැනීමක් මෘදුකාංග අවශ්යතා අභ්යන්තර රූප 530 MB මිදෙන්නට දැන් ඔවුන් තවදුරටත් අවශ්ය කරන්නේ සිට. අප එසේ නොකරන විට: යන්ත්රය මාරු කිරීම නවත්වයි.
පාරිතෝෂික කියවීම
මෙම පිළිතුරේ ශෛලියට කැමති ඕනෑම අයෙකුට (එයට හේතුව පැහැදිලි කරන්නේ කෙසේද , එසේ වන්නේ කෙසේද යන්න පැහැදිලි කිරීම), මම ඔබට යෝජනා කරන්නේ දොන් බොක්ස් හි අත්යවශ්ය COM හි පළමු පරිච්ඡේදය කියවන්න:
පිටු 35 කින් ඔහු ද්විමය වස්තු භාවිතා කිරීමේ ගැටළු පැහැදිලි කරන අතර ඔබේ ඇස් ඉදිරිපිට COM නිර්මාණය කරයි. COM හි හේතුව ඔබ තේරුම් ගත් පසු , ඉතිරි පිටු 300 පැහැදිලිව පෙනෙන අතර මයික්රොසොෆ්ට් ක්රියාත්මක කිරීම පිළිබඳ විස්තරාත්මකව.
මම හිතන්නේ මෙතෙක් වස්තූන් හෝ COM සමඟ ගනුදෙනු කළ සෑම ක්රමලේඛකයෙක්ම අවම වශයෙන් පළමු පරිච්ඡේදය කියවිය යුතුය. එය ඕනෑම දෙයක හොඳම පැහැදිලි කිරීමයි.
අමතර බෝනස් කියවීම
එරික් ලිපර්ට් විසින් ඔබ දන්නා සියල්ල වැරදියි
එබැවින් නිවැරදි අවසන් ලේඛනයක් ලිවීම ඇත්තෙන්ම ඉතා අපහසු වන අතර , මම ඔබට දිය හැකි හොඳම උපදෙස් වන්නේ උත්සාහ නොකිරීමයි .