ජාවා හි මතක කාන්දුවක් නිර්මාණය කරන්නේ කෙසේද?


3231

මට සම්මුඛ පරීක්ෂණයක් පැවැත්වූ අතර, ජාවා සමඟ මතක කාන්දුවක් ඇති කිරීමට මට නියම විය .
එය නිර්මාණය කිරීම ආරම්භ කරන්නේ කෙසේද යන්න පිළිබඳ කිසිදු හෝඩුවාවක් මට නොමැති බව අමුතුවෙන් කිව යුතු නැත.

උදාහරණයක් කුමක් විය හැකිද?


276
මම ජාවා කුණු එකතු භාවිතා කරන කියන්නම් කියලා, ඒ පැහැදිලි, "මතක කාන්දුවක්" ඔවුන්ගේ අර්ථ දැක්වීම ගැන තව ටිකක් විශේෂිත විය ඔවුන් ඇසීමට, - JVM දෝෂ මර්දන - ජාවා මතකය කාන්දු නොහැකි තරමක් එම මාර්ගය සී / සී ++ හැක. ඔබට කොතැනක හෝ වස්තුව ගැන සඳහනක් තිබිය යුතුය .
ඩැරියන්

372
බොහෝ පිළිතුරු වලදී මිනිසුන් එම අද්දර සිද්ධි සහ උපක්‍රම සොයමින් සිටින අතර කාරණය සම්පූර්ණයෙන්ම මග හැරී ඇති බව පෙනේ (IMO). නැවත කිසිදිනෙක භාවිතා නොකරන වස්තූන් සඳහා වැඩකට නැති යොමු කිරීම් තබා ඇති කේතයක් ඔවුන්ට පෙන්විය හැකි අතර ඒ සමඟම එම යොමු කිරීම් කිසි විටෙකත් අතහරින්නේ නැත; අවට ඇති වස්තූන් පිළිබඳ තවමත් සඳහනක් ඇති බැවින් එම අවස්ථා “සත්‍ය” මතක කාන්දු නොවන බව යමෙකුට පැවසිය හැකිය, නමුත් වැඩසටහන කිසි විටෙකත් එම යොමු නැවත භාවිතා නොකරන්නේ නම් සහ ඒවා කිසි විටෙකත් අතහරින්නේ නැතිනම් එය සම්පූර්ණයෙන්ම සමාන වේ (හා නරක ලෙස) සත්‍ය මතක කාන්දු වීම ".
ehabkost

62
අවංකවම මට "යන්න" ගැන ඇසූ සමාන ප්‍රශ්නය -1 දක්වා පහත බැස ඇති බව මට විශ්වාස කළ නොහැකිය. මෙන්න: stackoverflow.com/questions/4400311/… මූලික වශයෙන් මා කතා කරමින් සිටි මතක කාන්දු වන්නේ OP වෙත +200 ඉහළ නැංවූ අය වන අතර “Go” ට එකම ප්‍රශ්නයක් තිබේදැයි විමසීමට මට පහර දී අපහාස කරන ලදී. කෙසේ හෝ මට විශ්වාස නෑ සියලුම විකී දේවල් එතරම් විශිෂ්ට ලෙස ක්‍රියාත්මක වන බව.
SyntaxT3rr0r

74
Nt SyntaxT3rr0r - ඩැරියන්ගේ පිළිතුර රසික රසිකාවිය නොවේ. සමහර ජේවීඑම් වලට දෝෂ ඇති විය හැකි බව ඔහු පැහැදිලිවම පිළිගත්තේ එයින් අදහස් වන්නේ මතකය කාන්දු වන බවයි. මෙය මතක කාන්දු වීමට ඉඩ දෙන භාෂා පිරිවිතරයට වඩා වෙනස් වේ.
පීටර් රෙකෝර්

31
ha ඊහාබ්කොස්ට්: නැත, ඒවා සමාන නොවේ. (1) ඔබට මතකය නැවත ලබා ගැනීමේ හැකියාව ඇති අතර, “සත්‍ය කාන්දුවක” ඔබේ C / C ++ වැඩසටහන වෙන් කළ පරාසය අමතක කළද, නැවත යථා තත්ත්වයට පත් කිරීමට ආරක්ෂිත ක්‍රමයක් නොමැත. (2) පැතිකඩ පිළිබඳ ගැටළුව ඔබට ඉතා පහසුවෙන් හඳුනාගත හැකිය, මන්ද “පිපිරුම” ඇතුළත් වන්නේ කුමන වස්තූන් දැයි ඔබට දැක ගත හැකිය. (3) “සත්‍ය කාන්දුවීමක්” යනු නිසැක දෝෂයකි, නමුත් වැඩ අවසන් වන තෙක් බොහෝ වස්තූන් වටා තබා ගන්නා වැඩසටහනක් එය වැඩ කිරීමට අදහස් කරන ආකාරයෙහි හිතාමතාම කොටසක් විය හැකිය.
ඩැරියන්

Answers:


2311

පිරිසිදු ජාවා තුළ සත්‍ය මතක කාන්දුවක් (කේත ධාවනය කිරීමෙන් ප්‍රවේශ කළ නොහැකි නමුත් තවමත් මතකයේ ගබඩා කර ඇති) නිර්මාණය කිරීමට හොඳ ක්‍රමයක් මෙන්න:

  1. යෙදුම දිගුකාලීන නූල් සාදයි (හෝ ඊටත් වඩා වේගයෙන් කාන්දු වීමට නූල් තටාකයක් භාවිතා කරන්න).
  2. නූල් මඟින් පංතියක් පටවනු ලැබේ (විකල්පයක් ලෙස අභිරුචි) ClassLoader.
  3. පංතිය විශාල මතක ප්‍රමාණයක් වෙන් කරයි (උදා new byte[1000000]), ස්ථිතික ක්ෂේත්‍රයක් තුළ ඒ පිළිබඳව ප්‍රබල සඳහනක් ගබඩා කරයි, පසුව තමා වෙත යොමු කිරීමක් a ThreadLocal. අමතර මතකය වෙන් කිරීම විකල්පයකි (පන්ති අවස්ථාව කාන්දු වීම ප්‍රමාණවත්ය), නමුත් එය කාන්දු වීම වඩා වේගවත් කරයි.
  4. යෙදුම අභිරුචි පන්තියට හෝ ClassLoaderඑය පටවා ඇති සියලුම යොමු කිරීම් ඉවත් කරයි.
  5. නැවත නැවත කරන්න.

ThreadLocalඔරකල්හි ජේඩීකේ හි ක්‍රියාත්මක වන ආකාරය නිසා මෙය මතක කාන්දුවක් ඇති කරයි:

  • සෑම කෙනෙකුටම Threadපුද්ගලික ක්ෂේත්‍රයක් ඇත threadLocals, එය ඇත්ත වශයෙන්ම නූල්-දේශීය අගයන් ගබඩා කරයි.
  • මෙම සිතියමේ සෑම යතුරක්මThreadLocal වස්තුවක් පිළිබඳ දුර්වල සඳහනක් වන අතර එම නිසා එම ThreadLocalවස්තුව කසළ එකතු කිරීමෙන් පසුව එහි ප්‍රවේශය සිතියමෙන් ඉවත් කරනු ලැබේ.
  • නමුත් සෑම අගයක්ම ප්‍රබල යොමු කිරීමකි, එබැවින් අගයක් (සෘජුව හෝ වක්‍රව) ThreadLocalඑහි යතුර වන වස්තුව වෙත යොමු කළ විට, එම වස්තුව කුණු එකතු කිරීම හෝ නූල් ජීවත්වන තාක් සිතියමෙන් ඉවත් නොකෙරේ.

මෙම උදාහරණයේ දී, ශක්තිමත් යොමු දාමය මේ ආකාරයෙන් පෙනේ:

Threadවස්තුව → threadLocalsසිතියම example උදාහරණ පන්තියේ උදාහරණ → උදාහරණ පන්තිය → ස්ථිතික ThreadLocalක්ෂේත්‍ර → ThreadLocalවස්තුව.

( ClassLoaderකාන්දුව නිර්මාණය කිරීමේදී ඇත්ත වශයෙන්ම කාර්යභාරයක් ඉටු නොකරයි, මෙම අතිරේක යොමු දාමය නිසා එය කාන්දුව වඩාත් නරක අතට හැරේ: උදාහරණ පන්තිය ClassLoaderit it එය පටවා ඇති සියලුම පන්ති. බොහෝ ජේවීඑම් ක්‍රියාත්මක කිරීමේදී එය ඊටත් වඩා දරුණු විය ජාවා 7, පංති සහ පන්ති ClassLoaderකෙලින්ම පර්මජන් වලට වෙන් කර ඇති අතර ඒවා කිසි විටෙකත් කසළ එකතු කර නොතිබුණි.)

මෙම රටාවේ විචල්‍යතාවයක් වන්නේ යෙදුම් බහාලුම් (ටොම්කාට් වැනි) ඔබ නිතර භාවිතා කරන යෙදුම් නැවත නැවත යෙදවීම නම් පෙරනයක් වැනි මතකයක් කාන්දු විය හැක්කේ මන්ද යන්නයි ThreadLocal. මෙය සියුම් හේතු ගණනාවක් නිසා සිදුවිය හැකි අතර බොහෝ විට එය නිදොස් කිරීම සහ / හෝ නිවැරදි කිරීම දුෂ්කර ය.

යාවත්කාලීන කිරීම : බොහෝ අය එය දිගටම ඉල්ලා සිටින හෙයින්, මෙම හැසිරීම ක්‍රියාවෙන් පෙන්වන උදාහරණ කේතයක් මෙන්න .


186
+1 ClassLoader කාන්දුවීම් යනු JEE ලෝකයේ බහුලව දක්නට ලැබෙන වේදනාකාරී මතක කාන්දුවීම් වන අතර බොහෝ විට දත්ත පරිවර්තනය කරන තෙවන පාර්ශවීය ලිබ්ස් නිසා ඇතිවේ (BeanUtils, XML / JSON කෝඩෙක්ස්). ඔබේ යෙදුමේ මූල පංතියේ පැටවුමෙන් පිටත ලිබ් පටවා ඇති නමුත් ඔබේ පන්ති වෙත යොමු කිරීම් සිදු කරන විට මෙය සිදුවිය හැකිය (උදා: හැඹිලියෙන්). ඔබ ඔබේ යෙදුම අවලංගු කරන විට / නැවත යෙදවීමේදී යෙදුමේ පන්තියේ පැටවුම එකතු කිරීමට ජේවීඑම්ට නොහැකි වේ (එම නිසා එය පටවා ඇති සියලුම පංති), එබැවින් නැවත නැවත යෙදවීමෙන් යෙදුම් සේවාදායකය අවසානයේදී දැවී යයි. වාසනාවන්ත නම් ඔබට ClassCastException සමඟ හෝඩුවාවක් ලැබෙනු ඇත zxyAbc zxyAbc
earcam

7
ටොම්කාට් විසින් පටවා ඇති සියලුම පංතිවල ස්ථිතික විචල්‍යයන් භාවිතා කරයි, ටොම්කාට් සතුව දත්ත සමුදායන් සහ නරක කේතීකරණයක් ඇත (යම් කාලයක් ලබා ගැනීමට සහ නිවැරදි කිරීම් ඉදිරිපත් කිරීමට අවශ්‍යය), සහ අභ්‍යන්තර (කුඩා) වස්තූන් සඳහා හැඹිලියක් ලෙස සියලු මනස අවුල් කරන සමගාමී ලින්ක්ඩ්, සමගාමී ලින්ක්ඩ්කියු.නෝඩ් පවා වැඩි මතකයක් ගනී.
bestsss

57
+1: පන්තියේ පැටවුම් කාන්දු වීම බියකරු සිහිනයකි. මම ඒවා හදුනා ගැනීමට සති ගණන් උත්සාහ කළෙමි. කනගාටුදායක කාරණය නම්, @earcam පවසා ඇති පරිදි, ඒවා බොහෝ දුරට තෙවන පාර්ශවීය ලිබ්ස් නිසා ඇති වන අතර බොහෝ පැතිකඩකරුවන්ට මෙම කාන්දුවීම් හඳුනාගත නොහැක. Classloader කාන්දු වීම පිළිබඳව මෙම බ්ලොග් අඩවියේ හොඳ සහ පැහැදිලි පැහැදිලි කිරීමක් තිබේ. blogs.oracle.com/fkieviet/entry/…
ඒඩ්‍රියන් එම්

4
Ic නිකලස්: ඔබට විශ්වාසද? JRockit පෙරනිමියෙන් GC පන්තියේ වස්තූන් කරයි, සහ හොට්ස්පොට් එසේ නොවේ, නමුත් AFAIK JRockit හට තවමත් ThCLocal විසින් යොමු කරන ලද පන්තියක් හෝ පන්ති ලෝඩරයක් GC කළ නොහැක.
ඩැනියෙල් ප්‍රයිඩන්

6
ටොම්කාට් ඔබ වෙනුවෙන් මෙම කාන්දුවීම් හඳුනා ගැනීමට උත්සාහ කරනු ඇති අතර ඒවා ගැන අනතුරු අඟවයි: wiki.apache.org/tomcat/MemoryLeakProtection . නවතම අනුවාදය සමහර විට ඔබ සඳහා කාන්දුව පවා නිවැරදි කරනු ඇත.
මැතිතිස් බියර්මන්

1212

ස්ථිතික ක්ෂේත්‍ර රඳවා ගැනීමේ වස්තු යොමු [esp අවසන් ක්ෂේත්‍රය]

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}

String.intern()දිගු නූල් ඇමතීම

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you can't remove
str.intern();

(අනාවරණය නොකළ) විවෘත ධාරාවන් (ගොනුව, ජාලය ආදිය ...)

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

විවෘත නොකළ සම්බන්ධතා

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

ජේවීඑම් හි කසළ එකතු කරන්නාගෙන් ළඟා විය නොහැකි ප්‍රදේශ , එනම් ස්වදේශීය ක්‍රම මගින් මතකය වෙන් කිරීම

වෙබ් යෙදුම් වලදී, යෙදුම පැහැදිලිවම නවත්වන තුරු හෝ ඉවත් කරන තුරු සමහර වස්තු යෙදුම් විෂය පථයේ ගබඩා වේ.

getServletContext().setAttribute("SOME_MAP", map);

වැරදි හෝ නුසුදුසු JVM විකල්ප , එනම් noclassgcIBM JDK හි ඇති විකල්පය, භාවිතයට නොගත් පන්ති කසළ එකතු කිරීම වළක්වයි

IBM jdk සැකසුම් බලන්න .


178
සන්දර්භය සහ සැසි ගුණාංග “කාන්දුවීම්” බව මම එකඟ නොවෙමි. ඒවා දිගුකාලීන විචල්‍යයන් පමණි. ස්ථිතික අවසාන ක්ෂේත්‍රය නියතයක් හෝ වැඩි වශයෙන් අඩු වේ. සමහර විට විශාල නියතයන් වළක්වා ගත යුතුය, නමුත් එය මතක කාන්දුවක් ලෙස හැඳින්වීම සාධාරණ යැයි මම නොසිතමි.
ඉයන් මැක්ලෙයාර්ඩ්

80
(Unclosed) විවෘත ධාරා (ගොනු, ජාල ආදිය ...) , අවසන් කිරීම තුළ, සැබෑ සඳහා කාන්දු නොවන (ඊළඟ GC චක්රය පසු කෙරෙන) සමීප () (නියමිත කිරීමට යන්නේ close()සාමාන්යයෙන් finalizer දී පළ කළහ නැත නූල් සිට අවහිර කිරීමේ ක්‍රියාවක් විය හැක). වසා නොදැමීම නරක පුරුද්දකි, නමුත් එය කාන්දුවක් ඇති නොකරයි. අනාවරණය නොකළ java.sql.Connection එක සමානයි.
bestsss

33
බොහෝ බුද්ධිමත් ජේවීඑම් වල, එය පෙනෙන්නේ සංගීත පන්තියට එහි internහැෂ් ටේබල් අන්තර්ගතය පිළිබඳ දුර්වල සඳහනක් පමණක් ඇති බවයි . වැනි, එය වේ කුණු නිසි නොව කාන්දුවක් රැස් කළේය. (නමුත් IANAJP) mindprod.com/jgloss/interned.html#GC
මැට් බී.

42
ස්ථිතික ක්ෂේත්‍ර රඳවා ගැනීමේ වස්තු යොමු කිරීම [esp අවසන් ක්ෂේත්‍රය] මතක කාන්දුවක් වන්නේ කෙසේද ??
කනගවේළු සුගුමාර්

5
HcHao ඇත්ත. මා අත්විඳින අන්තරාය වන්නේ ධාරාව මගින් මතකය කාන්දු වීම නොවේ. ගැටලුව වන්නේ ඔවුන් විසින් ප්‍රමාණවත් මතකයක් කාන්දු නොවීමයි. ඔබට හසුරුවීම් විශාල ප්‍රමාණයක් කාන්දු විය හැකි නමුත් තවමත් මතකය ඕනෑ තරම් තිබේ. කසළ එකතු කරන්නා විසින් සම්පූර්ණ එකතුවක් කිරීමට කරදර නොවීමට තීරණය කළ හැකිය. මෙයින් අදහස් කරන්නේ අවසාන කාරකය කැඳවනු නොලබන බැවින් ඔබ හැසිරවිය නොහැකි බවයි. ගැටළුව වන්නේ, ඔබ කාන්දු වන ධාරාවන්ගෙන් මතකය ඉවර වීමට පෙර (සාමාන්‍යයෙන්) අවසන් ධාවකයන් ධාවනය වන නමුත් ඔබ මතකය හැර වෙනත් දෙයක් ඉවර වීමට පෙර එය කැඳවනු නොලැබේ.
පැට්‍රික් එම්

460

කළ යුතු සරලම දෙය නම් වැරදි (හෝ නොපවතින) සහිත හැෂ්සෙට් එකක් භාවිතා කිරීම hashCode()හෝ equals()ඉන්පසු “අනුපිටපත්” එකතු කිරීම ය. අනුපිටපත් නොසලකා හැරීම වෙනුවට, කට්ටලය කවදා හෝ වර්ධනය වන අතර ඔබට ඒවා ඉවත් කිරීමට නොහැකි වනු ඇත.

ඔබට මෙම නරක යතුරු / අංග වටා රැඳී සිටීමට අවශ්‍ය නම් ඔබට වැනි ස්ථිතික ක්ෂේත්‍රයක් භාවිතා කළ හැකිය

class BadKey {
   // no hashCode or equals();
   public final String key;
   public BadKey(String key) { this.key = key; }
}

Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.

68
ඇත්ත වශයෙන්ම, මූලද්‍රව්‍ය පන්තියට හැෂ් කේතයක් ලැබුණත් වැරදි ලෙස සමාන වුවත් ඔබට හැෂ්සෙට් එකකින් මූලද්‍රව්‍ය ඉවත් කළ හැකිය; කට්ටලය සඳහා අනුකාරකයක් ලබා ගෙන එය ඉවත් කිරීමේ ක්‍රමය භාවිතා කරන්න, මන්ද යත්, ක්‍රියාකාරකය සැබවින්ම ක්‍රියාත්මක වන්නේ යටින් පවතින ප්‍රවේශයන් මත මිස මූලද්‍රව්‍ය මත නොවේ. (සටහන කිසියම් පිළිවෙළින් hashCode / සමාන වන බව නොවේ කාන්දු තුඩු තරම්;. පෙරනිමි අගයන් සරල වස්තුව අනන්යතාව ක්රියාත්මක ඔබ අංග ලබා ගැනීමට හා සාමාන්යයෙන් ඒවා ඉවත් කළ හැකි නිසා)
Donal ගූගල්

12
To මම කියන්නට උත්සාහ කරන දෙය, මතක කාන්දුවක් පිළිබඳ ඔබේ අර්ථ දැක්වීමට මම එකඟ නොවෙමි. ඔබේ අනුකාරක ඉවත් කිරීමේ තාක්‍ෂණය කාන්දුවීමක් යටතේ බිංදු-පෑන් ලෙස මම සලකමි (ප්‍රතිසම දිගටම කරගෙන යාමට); බිංදු පෑන් නොසලකා කාන්දුව තවමත් පවතී.
corsiKa

94
මම එකඟ වෙමි, මෙය මතකය "කාන්දු වීමක්" නොවේ , මන්ද ඔබට හැෂ්සෙට් වෙත යොමු කිරීම් ඉවත් කර GC ආරම්භ වන තෙක් බලා සිටිය හැකි අතර, ප්‍රෙස්ටෝ! මතකය ආපසු යයි.
user541686

12
Nt SyntaxT3rr0r, ස්වාභාවිකවම මතක කාන්දු වීමට තුඩු දෙන භාෂාවේ යමක් තිබේදැයි විමසීමට මම ඔබේ ප්‍රශ්නය අර්ථකථනය කළෙමි. පිළිතුර නැත. මෙම ප්‍රශ්න අසන්නේ මතක කාන්දු වීමක් වැනි දෙයක් නිර්මාණය කිරීම සඳහා තත්වයක් නිර්මාණය කළ හැකිද යන්නයි. මෙම උදාහරණ කිසිවක් C / C ++ ක්‍රමලේඛකයෙකුට තේරුම් ගත හැකි ආකාරයට මතක කාන්දු නොවේ.
පීටර් ලෝරි

11
Et පීටර් ලෝරී: එසේම, ඔබ මේ ගැන සිතන්නේ කුමක්ද: "ඔබ වෙන් කළ මතකය අතින් නිදහස් කිරීමට අමතක නොකළහොත්, සී භාෂාවෙන් ස්වාභාවිකවම මතක කාන්දු වන කිසිවක් නොමැත" . බුද්ධිමය වංකකමට එය කෙසේ වනු ඇත්ද? කෙසේ වෙතත්, මට මහන්සියි: ඔබට අවසාන වචනය තිබිය හැකිය.
SyntaxT3rr0r

271

පහත දැක්වෙන්නේ ජාවා කාන්දු වන, අමතක වූ සවන්දෙන්නන්ගේ සම්මත අවස්ථාව, ස්ථිතික යොමු කිරීම්, හැෂ්මැප් වල ව්‍යාජ / වෙනස් කළ හැකි යතුරු හෝ ඔවුන්ගේ ජීවන චක්‍රය අවසන් කිරීමට කිසිදු අවස්ථාවක් නොමැතිව සිරවී ඇති නූල් පමණි.

  • File.deleteOnExit() - සෑම විටම නූල් කාන්දු වේ, නූල උපස්ථරයක් නම්, කාන්දුව ඊටත් වඩා දරුණු වේ (යටින් පවතින වර්‍ගය ද කාන්දු වේ)- ජාවා 7 උපස්ථරයේ ද පිටපත් කරයි char[], එබැවින් පසුකාලීනව අදාළ නොවේ ; An ඩැනියෙල්, ඡන්ද අවශ්‍ය නැත.

බොහෝ විට කළමනාකරණය නොකළ නූල් වල අන්තරාය පෙන්වීමට මම නූල් කෙරෙහි අවධානය යොමු කරමි, පැද්දීම ස්පර්ශ කිරීමට පවා කැමති නැත.

  • Runtime.addShutdownHookඉවත් නොකෙරේ ... පසුව ඉවත් කරන්න ෂට්ඩවුන්හූක් සමඟ පවා ආරම්භ නොකළ නූල් සම්බන්ධව ThreadGroup පන්තියේ දෝෂයක් නිසා එය එකතු නොවිය හැකි අතර ThreadGroup effectively ලදායී ලෙස කාන්දු වේ. ගොසිප් රවුටරයේ කාන්දු වීම JGroup සතුව ඇත.

  • නිර්මාණය කිරීම, නමුත් ආරම්භ නොකිරීම, Threadඉහත කාණ්ඩයටම අයත් වේ.

  • නූල් නිර්මාණය වන උරුම ContextClassLoaderසහ AccessControlContext, එකතු ThreadGroupඕනෑම InheritedThreadLocal, සියලු දෙනා යොමු සමස්ත පන්ති classloader රුවා සහ සියලු ස්ථිතික යොමු, හා, ජා-ජා සමඟ හැකි කාන්දු වේ. සුපිරි සරල ThreadFactoryඅතුරුමුහුණතක් සහිත සමස්ත jucExecutor රාමුව සමඟ එහි බලපෑම විශේෂයෙන් දැකිය හැකි නමුත් බොහෝ සංවර්ධකයින්ට සැඟවී ඇති අන්තරාය පිළිබඳ කිසිදු හෝඩුවාවක් නොමැත. බොහෝ පුස්තකාලයන් ඉල්ලීම පරිදි නූල් ආරම්භ කරයි (කර්මාන්තයේ ජනප්‍රිය පුස්තකාල ඕනෑවට වඩා).

  • ThreadLocalහැඹිලි; ඒවා බොහෝ අවස්ථාවල නපුරු ය. ThreadLocal මත පදනම් වූ සරල හැඹිලි සියල්ලම සෑම කෙනෙකුම දැක ඇති බව මට විශ්වාසයි, නරක ආරංචිය: ක්ලැස්ලෝඩර් සන්දර්භය තුළ අපේක්ෂිත ජීවිතයට වඩා නූල් දිගින් දිගටම යන්නේ නම්, එය පිරිසිදු කුඩා කාන්දුවකි. ඇත්ත වශයෙන්ම අවශ්‍ය නම් මිස ThreadLocal හැඹිලි භාවිතා නොකරන්න.

  • ඇමතුම් ThreadGroup.destroy()මෙම ThreadGroup කිසිදු නූල් ම වන විට, නමුත් එය තවමත් ළමා ThreadGroups කරයි. ThreadGroup එහි මවුපියන්ගෙන් ඉවත් කිරීම වළක්වන නරක කාන්දුවක්, නමුත් සියලුම දරුවන් ගණන් කළ නොහැකි තත්වයට පත්වේ.

  • WeakHashMap භාවිතා කිරීම සහ අගය (in) මඟින් යතුර යොමු කරයි. ගොඩවල් නොමැතිව සොයා ගැනීමට මෙය අපහසු දෙයකි. Weak/SoftReferenceආරක්‍ෂිත වස්තුව වෙත නැවත යොමු කිරීමක් කළ හැකි දීර් extended කරන ලද සියල්ලටම එය අදාළ වේ .

  • java.net.URLHTTP (S) ප්‍රොටෝකෝලය සමඟ භාවිතා කිරීම සහ (!) වෙතින් සම්පත් පූරණය කිරීම. මෙය විශේෂයි, KeepAliveCacheThreadGroup පද්ධතියේ නව නූලක් නිර්මාණය කරයි, එය වත්මන් නූල් වල සන්දර්භය පන්තියේ පැටවුම කාන්දු කරයි. සජීවී නූල් නොමැති විට පළමු ඉල්ලීම මත නූල් සාදනු ලැබේ, එබැවින් ඔබට වාසනාවන්ත විය හැකිය හෝ කාන්දු විය හැකිය. ජාවා 7 හි කාන්දුව දැනටමත් සවි කර ඇති අතර නූල් සාදන කේතය නිසි ලෙස සන්දර්භය පන්ති භාරය ඉවත් කරයි. තවත් අවස්ථා කිහිපයක් තිබේ (ImageFetcher වගේ, ද ස්ථාවර ) සමාන නූල් සෑදීම.

  • ඉදිකිරීම්කරු තුළ InflaterInputStreamගමන් කිරීම භාවිතා new java.util.zip.Inflater()කිරීම ( PNGImageDecoderනිදසුනක් ලෙස) සහ end()ගිනි අවුලුවන ඇමතුම නොකිරීම. හොඳයි, ඔබ ඉදිකිරීම්කරු තුළ සාධාරණ ලෙස සමත් වුවහොත් newකිසිදු අවස්ථාවක් නැත ... ඔව්, close()ධාරාව ඇමතීමෙන් එය පාලක පරාමිතිය ලෙස අතින් සම්මත වුවහොත් එය පුපුරා යන්නේ නැත. මෙය සත්‍ය කාන්දුවීමක් නොවන බැවින් එය අවසන් කරන්නා විසින් මුදා හරිනු ඇත ... එය අවශ්‍ය යැයි හැඟෙන විට. ඒ මොහොත දක්වාම එය ස්වදේශික මතකය ඉතා නරක ලෙස අනුභව කරන අතර එය ලිනක්ස් oom_killer ද unity ුවම් නොලබා ක්‍රියාවලිය විනාශ කිරීමට හේතු වේ. ප්රධාන ගැටළුව වන්නේ ජාවා හි අවසන් කිරීම ඉතා විශ්වාසදායක නොවන අතර G1 එය 7.0.2 වන තෙක් නරක අතට හැරීමයි. කතාවේ සදාචාරය: ඔබට හැකි ඉක්මනින් දේශීය සම්පත් නිදහස් කරන්න; අවසන් කරන්නා ඉතා දුර්වලයි.

  • එකම නඩුව java.util.zip.Deflater. ජාවා හි ඩෙෆ්ලේටර් මතක කුසගින්නෙන් පෙළෙන බැවින් මෙය වඩාත් නරක ය, එනම් සෑම විටම බිටු 15 ක් (උපරිම) සහ මතක මට්ටම් 8 ක් (9 උපරිම වේ) ස්වදේශීය මතකයේ කිලෝ සිය ගණනක් වෙන් කරයි. වාසනාවකට මෙන්, Deflaterබහුලව භාවිතා නොවන අතර මගේ දැනුමට අනුව JDK හි කිසිදු අනිසි භාවිතයක් නොමැත. end()ඔබ අතින් Deflaterහෝ නිර්මාණය කරන්නේ නම් සැමවිටම අමතන්න Inflater. අන්තිම දෙකේ හොඳම කොටස: ලබා ගත හැකි සාමාන්‍ය පැතිකඩ මෙවලම් හරහා ඔබට ඒවා සොයාගත නොහැක.

(ඉල්ලීම පරිදි මට හමු වූ තවත් කාලය නාස්ති කිහිපයක් එකතු කළ හැකිය.)

වාසනාව සහ ආරක්ෂිතව සිටින්න; කාන්දුවීම් නපුරු ය!


23
Creating but not starting a Thread...අහෝ, ශතවර්ෂ කිහිපයකට පෙර මට මෙය දරුණු ලෙස දෂ්ට විය! (ජාවා 1.3)
ලියොන්බ්ලෝ

@leonbloy, නූල් සමූහයට කෙලින්ම එකතු කිරීම නිසා එය ඊටත් වඩා නරක වීමට පෙර, ආරම්භ නොකිරීම යනු ඉතා තදින් කාන්දු වීමකි. එය unstartedගණනය කිරීම වැඩි කරනවා පමණක් නොව, නූල් කණ්ඩායම විනාශ කිරීමෙන් වළක්වයි (අඩු නපුර නමුත් තවමත් කාන්දුවක්)
bestsss

ඔබට ස්තුතියි! " ThreadGroup.destroy()ThreadGroup හි නූල් නොමැති විට ඇමතීම ..." ඇදහිය නොහැකි තරම් සියුම් දෝෂයකි; මම මෙය පැය ගණනක් ලුහුබඳිමින්, නොමඟ ගියෙමි, මන්ද මගේ පාලනයේ නූල් ගණනය කිරීමෙන් GUI කිසිවක් පෙන්වූයේ නැත, නමුත් නූල් කණ්ඩායම සහ, අවම වශයෙන් එක් ළමා කණ්ඩායමක්වත් නොයනු ඇත.
ලෝරන්ස් ඩොල්

1
est බෙස්ට්ස්: මට කුතුහලයක් ඇත, ජේවීඑම් වසා දැමීමේදී එය ක්‍රියාත්මක වන බැවින්, වසා දැමීමේ කොක්කක් ඉවත් කිරීමට ඔබට අවශ්‍ය ඇයි?
ලෝරන්ස් ඩොල්

203

මෙහි බොහෝ උදාහරණ "ඉතා සංකීර්ණ" ය. ඒවා අද්දර නඩු. මෙම උදාහරණ සමඟ, ක්‍රමලේඛකයා වැරැද්දක් කර ඇත (සමාන / හැෂ්කෝඩ් නැවත අර්ථ දැක්වීම වැනි), හෝ ජේවීඑම් / ජාවා (ස්ථිතික සමඟ පන්තියේ බර ...) හි මුල්ලක නඩුවකින් දෂ්ට කර ඇත. මම හිතන්නේ එය සම්මුඛ පරීක්‍ෂකවරයකුට අවශ්‍ය ආදර්ශය හෝ වඩාත් පොදු අවස්ථාව නොවේ.

නමුත් මතක කාන්දුවීම් සඳහා වඩාත් සරල අවස්ථා තිබේ. කසළ එකතු කරන්නා නිදහස් කරන්නේ තවදුරටත් සඳහන් නොකරන දේ පමණි. ජාවා සංවර්ධකයින් වන අපි මතකය ගැන තැකීමක් නොකරමු. අවශ්‍ය විටෙක අපි එය වෙන් කර ස්වයංක්‍රීයව නිදහස් වීමට ඉඩ දෙමු. හොඳයි.

නමුත් ඕනෑම දිගුකාලීන යෙදුමක් හවුල් තත්වයට පත්වේ. එය ඕනෑම දෙයක් විය හැකිය, සංඛ්‍යාන, සිංගල්ටන් ... බොහෝ විට සුළු නොවන යෙදුම් සංකීර්ණ වස්තු ප්‍රස්ථාර සෑදීමට නැඹුරු වේ. එකතුවක් වෙතින් එක් වස්තුවක් ඉවත් කිරීමට ශුන්‍ය හෝ බොහෝ විට අමතක කිරීමට අමතක කිරීම මතක කාන්දු වීමක් සඳහා ප්‍රමාණවත් වේ.

ඇත්ත වශයෙන්ම සියලු ආකාරයේ සවන්දෙන්නන් (UI සවන්දෙන්නන් වැනි), හැඹිලි හෝ දිගු කාලීනව බෙදාගත් ඕනෑම රාජ්‍යයක් නිසි ලෙස හසුරුවන්නේ නැත්නම් මතක කාන්දු වීමක් ඇති කරයි. තේරුම් ගත යුතු දෙය නම් මෙය ජාවා කෝනර් නඩුවක් හෝ කසළ එකතු කරන්නාගේ ගැටලුවක් නොවන බවයි. එය නිර්මාණ ගැටළුවක්. අපි දිගු කාලීන වස්තුවකට සවන්දෙන්නෙකු එක් කරන ලෙස අපි සැලසුම් කරමු, නමුත් තවදුරටත් අවශ්‍ය නොවන විට අපි සවන්දෙන්නන් ඉවත් නොකරමු. අපි වස්තු හැඹිලි, නමුත් ඒවා හැඹිලියෙන් ඉවත් කිරීමට අපට උපාය මාර්ගයක් නොමැත.

ගණනය කිරීමකින් අවශ්‍ය වන පෙර තත්වය ගබඩා කරන සංකීර්ණ ප්‍රස්ථාරයක් අප සතුව ඇත. නමුත් පෙර පැවති රාජ්‍යය ඊට පෙර සහ එසේ රාජ්‍යයට සම්බන්ධ වේ.

හරියට අපි SQL සම්බන්ධතා හෝ ගොනු වසා දැමිය යුතුයි. එකතුවෙන් මූලද්‍රව්‍ය ශුන්‍ය කිරීමට සහ ඉවත් කිරීමට අපට නිසි යොමු කිරීම් අවශ්‍ය වේ. අපට නිසි හැඹිලි ක්‍රමෝපායන් ඇත (උපරිම මතක ප්‍රමාණය, මූලද්‍රව්‍ය ගණන හෝ ටයිමර). සවන්දෙන්නෙකුට දැනුම් දීමට ඉඩ දෙන සියලුම වස්තූන් ඇඩ්ලිස්ටනර් සහ ඉවත් කිරීමේ ලැයිස්තුව යන දෙකම සැපයිය යුතුය. මෙම දැනුම්දීම් තවදුරටත් භාවිතා නොකරන විට, ඔවුන් ඔවුන්ගේ සවන්දෙන්නන්ගේ ලැයිස්තුව ඉවත් කළ යුතුය.

මතක කාන්දුවක් සැබවින්ම සැබවින්ම හැකි අතර එය සම්පූර්ණයෙන්ම පුරෝකථනය කළ හැකිය. විශේෂ භාෂා විශේෂාංග හෝ මුල්ලක අවස්ථා අවශ්‍ය නොවේ. මතක කාන්දුවීම් යනු යමක් නැතිවී ඇති බවට හෝ නිර්මාණ ගැටළු ඇති බවට දර්ශකයකි.


24
වෙනත් පිළිතුරු වලදී මිනිසුන් එම අද්දර නඩු සහ උපක්‍රම සොයන අතර එය සම්පූර්ණයෙන්ම මග හැරී ඇති බව පෙනේ. නැවත කිසි විටෙකත් භාවිතා නොකරන වස්තූන් සඳහා වැඩකට නැති යොමු කිරීම් තබා ඇති කේත පෙන්වීමට ඔවුන්ට හැකි අතර එම යොමු කිසි විටෙකත් ඉවත් නොකරන්න; අවට ඇති වස්තූන් පිළිබඳ තවමත් සඳහනක් ඇති බැවින් එම අවස්ථා “සත්‍ය” මතක කාන්දු නොවන බව යමෙකුට පැවසිය හැකිය, නමුත් වැඩසටහන කිසි විටෙකත් එම යොමු නැවත භාවිතා නොකරන්නේ නම් සහ ඒවා කිසි විටෙකත් අතහරින්නේ නැතිනම් එය සම්පූර්ණයෙන්ම සමාන වේ (හා නරක ලෙස) සත්‍ය මතක කාන්දු වීම ".
ehabkost

Ic නිකොලාස් බෝස්කට්: "මතක කාන්දු වීම සැබවින්ම සත්‍යයකි " බොහොම ස්තුතියි. +15 ඉහළට. හොඳයි. Go භාෂාව පිළිබඳ ප්‍රශ්නයක පරිශ්‍රය ලෙස මම මෙහි කෑගැසුවෙමි : stackoverflow.com/questions/4400311 මෙම ප්‍රශ්නයට තවමත් negative ණාත්මක අගයන් ඇත :(
SyntaxT3rr0r

ජාවා සහ .නෙට් හි ඇති GC යම් අර්ථයකින් පුරෝකථනය කර ඇත්තේ වෙනත් වස්තූන් ගැන සඳහනක් ඇති වස්තූන්ගේ උපකල්පන ප්‍රස්ථාරය මත ය. යථාර්ථය නම්, “සැලකිලිමත්” සම්බන්ධතා නිරූපණය නොකරන යොමු ප්‍රස්ථාරයේ දාර පැවතිය හැකි අතර, වස්තුවකට වෙනත් වස්තුවක පැවැත්ම ගැන සැලකිලිමත් විය හැකි අතර සෘජු හෝ වක්‍ර යොමු මාර්ගයක් නොමැති වුවද (භාවිතා කිරීම WeakReference) එක සිට අනෙකට. වස්තු යොමු
කිරීමක

... සහ PhantomReferenceවස්තුවක් ඒ ගැන සැලකිලිමත් වන කිසිවෙකු නොමැති බව සොයාගත හොත් (ඒ හා සමාන ආකාරයකින් ) පද්ධතියට දැනුම් දීම් ලබා දෙන්න . WeakReferenceතරමක් සමීප වන නමුත් එය භාවිතා කිරීමට පෙර එය ශක්තිමත් යොමුවකට පරිවර්තනය කළ යුතුය; ප්‍රබල යොමුව පවතින අතර GC චක්‍රයක් සිදුවුවහොත්, ඉලක්කය ප්‍රයෝජනවත් යැයි උපකල්පනය කෙරේ.
සුපර් කැට්

මෙය මගේ පිළිතුරයි නිවැරදි පිළිතුර. අපි මීට වසර ගණනාවකට පෙර සමාකරණයක් ලිව්වෙමු. කෙසේ හෝ අපි කලින් පැවති තත්වය වර්තමාන තත්වයට අහම්බෙන් සම්බන්ධ කළේ මතක කාන්දුවක් නිර්මාණය කරමිනි. නියමිත කාල සීමාවක් නිසා අපි කිසි විටෙකත් මතක කාන්දුව විසඳුවේ නැත, නමුත් එය ලේඛනගත කිරීමෙන් එය «අංගයක් made බවට පත් කළෙමු.
nalply

164

පිළිතුර මුළුමනින්ම රඳා පවතින්නේ සම්මුඛ පරීක්‍ෂකවරයා ඔවුන් අසන්නේ යැයි සිතූ දේ මත ය.

ජාවා කාන්දු වීම ප්‍රායෝගිකව කළ හැකිද? ඇත්ත වශයෙන්ම එය එසේ වන අතර අනෙක් පිළිතුරු වල උදාහරණ ඕනෑ තරම් තිබේ.

නමුත් මෙටා ප්‍රශ්න කිහිපයක් අසනු ලැබිය හැකිද?

  • න්‍යායාත්මකව “පරිපූර්ණ” ජාවා ක්‍රියාත්මක කිරීම කාන්දුවීම් වලට ගොදුරු විය හැකිද?
  • න්‍යාය සහ යථාර්ථය අතර වෙනස අපේක්ෂකයා තේරුම් ගන්නේද?
  • කසළ එකතු කරන ආකාරය අපේක්ෂකයාට තේරෙනවාද?
  • එසේත් නැතිනම් කසළ එකතු කිරීම පරිපූර්ණ අවස්ථාවකදී ක්‍රියා කරන්නේ කෙසේද?
  • ස්වදේශීය අතුරුමුහුණත් හරහා වෙනත් භාෂාවන් ඇමතිය හැකි බව ඔවුන් දන්නවාද?
  • වෙනත් භාෂාවලින් මතකය කාන්දු වීමට ඔවුන් දන්නවාද?
  • මතක කළමනාකරණය යනු කුමක්ද සහ ජාවා හි තිරය පිටුපස සිදුවන්නේ කුමක්ද යන්න අපේක්ෂකයා දන්නවාද?

මම ඔබේ මෙටා ප්‍රශ්නය කියවන්නේ "මෙම සම්මුඛ පරීක්ෂණයේදී මට භාවිතා කළ හැකි පිළිතුර කුමක්ද" යන්නයි. ඒ නිසා මම ජාවා වෙනුවට සම්මුඛ පරීක්ෂණ කුසලතා කෙරෙහි අවධානය යොමු කරන්නෙමි. සම්මුඛ පරීක්ෂණයකදී ඔබ ජාවා කාන්දු කරන්නේ කෙසේදැයි දැන ගැනීමට අවශ්‍ය ස්ථානයක සිටීමට වඩා සම්මුඛ සාකච්ඡාවකදී ප්‍රශ්නයකට පිළිතුර නොදැනීමේ තත්වය ඔබ නැවත නැවත කිරීමට ඉඩ ඇතැයි මම විශ්වාස කරමි. එබැවින්, මෙය උපකාරී වනු ඇතැයි අපේක්ෂා කරමු.

සම්මුඛ පරීක්ෂණ සඳහා ඔබට වර්ධනය කළ හැකි වැදගත්ම කුසලතාවන් වන්නේ ප්‍රශ්නවලට සක්‍රියව ඇහුම්කන් දීමට ඉගෙන ගැනීම සහ සම්මුඛ පරීක්ෂක සමඟ ඔවුන්ගේ අභිප්‍රාය උපුටා ගැනීම සඳහා වැඩ කිරීමයි. මෙය ඔවුන්ගේ ප්‍රශ්නයට ඔවුන්ට අවශ්‍ය ආකාරයට පිළිතුරු සැපයීමට පමණක් නොව, ඔබට වැදගත් සන්නිවේදන කුසලතා ඇති බව පෙන්වයි. බොහෝ සමාන දක්ෂතා ඇති සංවර්ධකයින් අතර තේරීමකට එළඹෙන විට, ඔවුන් සෑම අවස්ථාවකදීම ප්‍රතිචාර දැක්වීමට පෙර සවන් දෙන, සිතන සහ තේරුම් ගන්නා තැනැත්තා මම බඳවා ගන්නෙමි.


22
මම එම ප්‍රශ්නය ඇසූ සෑම විටම මම ඉතා සරල පිළිතුරක් සොයමි - පෝලිමක් වැඩීම දිගටම කරගෙන යන්න, අන්තිමේදී ඩීබී යනාදිය වසා නොදමන්න, අමුතු පන්ති භාරකරු / නූල් විස්තර නොවේ, එයින් අදහස් කරන්නේ ඔවුන් ඔබට gc ට කළ හැකි හා කළ නොහැකි දේ තේරුම් ගෙන ඇති බවයි. මම අනුමාන කරන පරිදි ඔබ සම්මුඛ පරීක්ෂණයට ලක් කරන රැකියාව මත රඳා පවතී.
ඩේව්සී

කරුණාකර මගේ ප්‍රශ්නය දෙස බලන්න, ස්තූතියි stackoverflow.com/questions/31108772/…
ඩැනියෙල් නිව්ටවුන්

130

ඔබට ජේඩීබීසී තේරෙන්නේ නැත්නම් පහත දැක්වෙන්නේ අර්ථ විරහිත උදාහරණයකි . හෝ JDBC සමීප කිරීමට සංවර්ධක අපේක්ෂා ආකාරය අවම වශයෙන් Connection, Statementහා ResultSetක්රියාත්මක කිරීම මත රඳා ඔවුන් උපයෝගි හෝ ඔවුන්ට යොමු අහිමි, ඒ වෙනුවට පෙර අවස්ථා finalize.

void doWork()
{
   try
   {
       Connection conn = ConnectionFactory.getConnection();
       PreparedStatement stmt = conn.preparedStatement("some query"); // executes a valid query
       ResultSet rs = stmt.executeQuery();
       while(rs.hasNext())
       {
          ... process the result set
       }
   }
   catch(SQLException sqlEx)
   {
       log(sqlEx);
   }
}

ඉහත සඳහන් ගැටළුව නම්, Connectionවස්තුව වසා නොමැති අතර, එම නිසා කසළ එකතු කරන්නා අවට පැමිණ එය ළඟා විය නොහැකි බව දකින තුරු භෞතික සම්බන්ධතාවය විවෘතව පවතිනු ඇත. GC විසින් මෙම finalizeක්‍රමයට ආයාචනා කරනු ඇත , නමුත් ක්‍රියාත්මක නොකරන JDBC ධාවක ඇත finalize, අවම වශයෙන් Connection.closeක්‍රියාත්මක වන ආකාරයටම නොවේ. එහි ප්‍රති behavior ලයක් ලෙස ළඟා විය නොහැකි වස්තූන් නිසා මතකය නැවත ගොඩ ගන්නා අතර, Connectionවස්තුව හා සම්බන්ධ සම්පත් (මතකය ද ඇතුළුව) නැවත ගොඩ නොගනු ඇත.

කොහෙද එවැනි අවස්ථාවක දී Connectionඇති finalizeක්රමය සියල්ල පිරිසිදු නැත, එක් ඇත්තටම දත්ත සමුදා සේවාදායකයට භෞතික සම්බන්ධයක් නම් එය (එම දත්ත සමුදා සේවාදායකය අවසානයේ ඇති සම්බන්ධය ජීවත් නොවන බව සංඛ්යා තෙක්, කැළි කසළ පැදි කීපයක් ගත වන බව ඔබට සිතෙන්න පුළුවන් ), සහ වසා දැමිය යුතුය.

ජේඩීබීසී රියදුරු ක්‍රියාත්මක finalizeකළත්, අවසන් කිරීමේ දී ව්‍යතිරේකයන් විසි කළ හැකිය. එහි ප්‍රති behavior ලයක් ලෙස දැන් “අක්‍රිය” වස්තුව හා සම්බන්ධ ඕනෑම මතකයක් නැවත ලබා නොගනු ඇත finalize.

වස්තු අවසන් කිරීමේදී ව්‍යතිරේකවලට මුහුණ දීමේ ඉහත සිදුවීම මතක කාන්දුවකට තුඩු දිය හැකි තවත් සිදුවීමක් හා සම්බන්ධ වේ - වස්තු නැවත නැඟිටීම. වස්තු නැවත නැඟිටීම බොහෝ විට සිදු කරනුයේ වෙනත් වස්තුවකින් අවසාන වස්තුවෙන් ප්‍රබල සඳහනක් නිර්මාණය කිරීමෙනි. වස්තු නැවත නැඟිටීම අනිසි ලෙස භාවිතා කරන විට එය මතක කාන්දුවීම් වලට හේතු වේ.

ඔබට උපකල්පනය කළ හැකි තවත් බොහෝ උදාහරණ තිබේ - වැනි

  • කළමනාකරණය අ Listඔබ ලැයිස්තුවට පමණක් එකතු කරන සහ එයින් මකා නොදමන අවස්ථාවක් (ඔබට තවදුරටත් අවශ්‍ය නොවන අංග ඉවත් කළ යුතු වුවද), හෝ
  • විවෘත කිරීම SocketහෝFile s , නමුත් ඒවා තවදුරටත් අවශ්‍ය නොවන විට ඒවා වසා නොදැමීම ( Connectionපන්තිය සම්බන්ධ ඉහත උදාහරණයට සමානය ).
  • ජාවා ඊඊ යෙදුමක් ගෙන එන විට සිංගල්ටන් බෑම නොකිරීම. පෙනෙන විදිහට, සිංගල්ටන් පංතිය පටවා ඇති පන්තියේ පැටවුම පන්තියට යොමු කිරීමක් රඳවා ගනු ඇත, එබැවින් සිංගල්ටන් උදාහරණය කිසි විටෙකත් එකතු නොකෙරේ. යෙදුමේ නව අවස්ථාවක් යෙදවූ විට, සාමාන්‍යයෙන් නව පංති පැටවුමක් සාදනු ලබන අතර, තනි පන්තිය නිසා කලින් පන්තියේ පැටවුම දිගටම පවතිනු ඇත.

98
ඔබ සාමාන්‍යයෙන් මතක සීමාවට පැමිණීමට පෙර උපරිම විවෘත සම්බන්ධතා සීමාවට ළඟා වනු ඇත. මා දන්නේ මන්දැයි මගෙන් අහන්න එපා ...
දෘඩාංග

ඔරකල් ජේඩීබීසී රියදුරු මෙය කිරීම සම්බන්ධයෙන් කුප්‍රකටය.
chotchki

Ard හාර්ඩ්වෙයාර්ගුයි Connection.closeමගේ සියලුම SQL ඇමතුම් අවසාන වාරණයට ඇතුළත් කරන තෙක් මම SQL දත්ත සමුදායන්ගේ සම්බන්ධතා සීමාවන්ට පහර දුන්නා . අමතර විනෝදය සඳහා මම දිගු කාලීනව ක්‍රියාත්මක වන ඔරකල් ගබඩා කළ ක්‍රියා පටිපාටි කිහිපයක් ඇමතුවෙමි.
මයිකල් ෂොප්සින්

Ard හාර්ඩ්වෙයාර්ගුයි එය සිත්ගන්නා සුළු නමුත් සියලු පරිසරයන් සඳහා සත්‍ය සම්බන්ධතා සීමාවන්ට පහර දීම ඇත්තෙන්ම අවශ්‍ය නොවේ. උදාහරණයක් ලෙස, වෙබ්ලොජික් යෙදුම් සේවාදායකයේ යොදවා ඇති යෙදුමක් සඳහා 11g විශාල වශයෙන් සම්බන්ධතා කාන්දු වීම මම දැක ඇත්තෙමි. නමුත් අස්වනු නෙළීමේ විකල්පයක් හේතුවෙන් මතක කාන්දු වන අතරතුර දත්ත සමුදා සම්බන්ධතා පැවතුනි. සියලු පරිසරයන් ගැන මට විශ්වාස නැත.
අසීම් ​​බන්සාල්

මගේ අත්දැකීම් අනුව ඔබ සම්බන්ධතාවය වසා දැමුවද ඔබට මතක කාන්දුවක් ලැබේ. ඔබ මුලින්ම ResultSet සහ PreparedStatement වසා දැමිය යුතුයි. OutOfMemoryErrors නිසා පැය ගණනක් හෝ දින ගණනක් වැඩ කිරීමෙන් පසු නැවත නැවත බිඳ වැටුණු සේවාදායකයක් මා සතුව තිබේ නම්, මම එය කිරීමට පටන් ගන්නා තෙක්.
Bjørn Stenfeldt

119

විභව මතක කාන්දුවක් සඳහා සරලම උදාහරණයන්ගෙන් එකක් වන අතර එය වළක්වා ගන්නේ කෙසේද යන්න ArrayList.remove (int) ක්‍රියාත්මක කිරීම වේ:

public E remove(int index) {
    RangeCheck(index);

    modCount++;
    E oldValue = (E) elementData[index];

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index + 1, elementData, index,
                numMoved);
    elementData[--size] = null; // (!) Let gc do its work

    return oldValue;
}

ඔබ එය ඔබම ක්‍රියාත්මක කරන්නේ නම්, තවදුරටත් භාවිතා නොකරන ( elementData[--size] = null) අරාව මූලද්‍රව්‍යය ඉවත් කිරීමට ඔබ සිතුවාද ? එම සඳහන මගින් විශාල වස්තුවක් පණපිටින් තබා ගත හැකිය ...


5
මෙහි මතකය කාන්දු වන්නේ කොහේද?
rds

28
@maniek: මෙම කේතය මතක කාන්දු වීමක් පෙන්නුම් කරන බව ඇඟවීමට මම අදහස් නොකළෙමි. අහම්බෙන් වස්තු රඳවා තබා ගැනීම වළක්වා ගැනීම සඳහා සමහර විට පැහැදිලි නොවන කේතයක් අවශ්‍ය බව පෙන්වීමට මම එයට උපුටා දැක්වුවෙමි.
meriton

RangeCheck යනු කුමක්ද (දර්ශකය); ?
කෝරේ ටුගෙයි

6
ජොෂුවා බ්ලොච් මෙම උදාහරණය Java ලදායී ජාවාහි දී ස්ටැක්ස් සරල ලෙස ක්‍රියාත්මක කිරීම පෙන්වයි. ඉතා හොඳ පිළිතුරක්.
කුලී

නමුත් එය අමතක වුව ද එය සැබෑ මතක කාන්දුවක් නොවනු ඇත. මූලද්‍රව්‍යය තවමත් පරාවර්තනය සමඟ ආරක්ෂිතව ප්‍රවේශ වනු ඇත, එය ලැයිස්තු අතුරුමුහුණත හරහා පැහැදිලිව හා කෙලින්ම ප්‍රවේශ විය නොහැක, නමුත් වස්තුව සහ යොමු කිරීම තවමත් පවතින අතර ආරක්ෂිතව ප්‍රවේශ විය හැකිය.
DGoiko

68

ඔබට තවදුරටත් මතක මතක කාන්දු වීමක් අවශ්‍ය නොවන වස්තූන් වෙත යොමු කිරීම් කරන ඕනෑම වේලාවක. ජාවා වැඩසටහන් වල මතක කාන්දුවීම් හැසිරවීම ජාවා තුළ මතක කාන්දු වන ආකාරය සහ ඒ සඳහා ඔබට කළ හැකි දේ පිළිබඳ උදාහරණ බලන්න .


14
මෙය "කාන්දුවක්" යැයි මම විශ්වාස නොකරමි. එය දෝෂයක් වන අතර එය වැඩසටහන සහ භාෂාව සැලසුම් කිරීමෙනි. කාන්දුවක් යනු කිසිදු සඳහනක් නොමැතිව එය වටා එල්ලෙන වස්තුවකි .
user541686

29
E මෙහර්දාඩ්: එය සියලු භාෂාවන්ට සම්පූර්ණයෙන්ම අදාළ නොවන එක් පටු අර්ථ දැක්වීමක් පමණි. ඕනෑම මතකයක් කාන්දු වීම වැඩසටහනේ දුර්වල සැලසුම නිසා ඇති වූ දෝෂයක් යැයි මම තර්ක කරමි .
බිල් ද කටුස්සා

9
E මෙහර්දාඩ්: ...then the question of "how do you create a memory leak in X?" becomes meaningless, since it's possible in any language. ඔබ එම නිගමනයට එළඹෙන්නේ කෙසේදැයි මට නොපෙනේ. ඇත අඩු ඕනෑම නිර්වචනය විසින් ජාවා මතක කාන්දුවක් නිර්මාණය කිරීම සඳහා ක්රම. එය අනිවාර්යයෙන්ම තවමත් වලංගු ප්‍රශ්නයකි.
බිල් ද කටුස්

7
Ee 31eee384: ඔබේ වැඩසටහන කිසි විටෙකත් භාවිතා කළ නොහැකි වස්තු මතකයේ තබා ගන්නේ නම්, තාක්ෂණික වශයෙන් එය කාන්දු වූ මතකයයි. ඔබට වඩා විශාල ගැටළු ඇති බව ඇත්ත වශයෙන්ම එය වෙනස් නොවේ.
බිල් ද කටුස්සා

8
Ee 31eee384: එය එසේ නොවන බව ඔබ දන්නේ නම්, එසේ විය නොහැක. වැඩසටහන, ලියා ඇති පරිදි, කිසි විටෙකත් දත්ත වලට ප්‍රවේශ නොවනු ඇත.
බිල් ද කටුස්

51

Sun.misc.Unsafe පන්තිය සමඟ මතක කාන්දු වීමට ඔබට හැකිය . ඇත්ත වශයෙන්ම මෙම සේවා පන්තිය විවිධ සම්මත පන්තිවල භාවිතා වේ (උදාහරණයක් ලෙස java.nio පන්තිවල). ඔබට මෙම පංතියේ නිදසුන කෙලින්ම නිර්මාණය කළ නොහැක , නමුත් ඔබට එය කිරීමට පරාවර්තනය භාවිතා කළ හැකිය .

කේතය සූර්යග්‍රහණ IDE හි සම්පාදනය නොකරයි - විධානය භාවිතා කර එය javacසම්පාදනය කරන්න (සම්පාදනය කිරීමේදී ඔබට අනතුරු ඇඟවීම් ලැබෙනු ඇත)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import sun.misc.Unsafe;


public class TestUnsafe {

    public static void main(String[] args) throws Exception{
        Class unsafeClass = Class.forName("sun.misc.Unsafe");
        Field f = unsafeClass.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        System.out.print("4..3..2..1...");
        try
        {
            for(;;)
                unsafe.allocateMemory(1024*1024);
        } catch(Error e) {
            System.out.println("Boom :)");
            e.printStackTrace();
        }
    }

}

1
වෙන් මතක කුණු එකතු කිරීම සඳහා නොපෙනෙන
stemm

4
වෙන් කළ මතකය ජාවාට අයත් නොවේ.
bestsss

මෙම සූර්යයා / ඔරකල් jvm විශේෂිතද? උදා: මෙය IBM හි වැඩ කරයිද?
බර්ලින් බ්‍රවුන්

2
මතකය නිසැකවම "ජාවාට අයත් වේ", අවම වශයෙන් එය i) එය වෙනත් කිසිවෙකුට ලබා ගත නොහැක, ii) ජාවා යෙදුමෙන් පිටවන විට එය නැවත පද්ධතියට ලැබෙනු ඇත. එය ජේවීඑම් වෙතින් පිටත ය.
මයිකල් ඇන්ඩර්සන්

3
මෙය සූර්යග්‍රහණයෙන් ගොඩනැඟෙනු ඇත (අවම වශයෙන් මෑත සංස්කරණ වලදී) නමුත් ඔබට සම්පාදක සැකසුම් වෙනස් කිරීමට අවශ්‍ය වනු ඇත: කවුළුව> මනාපයන්> ජාවා> සම්පාදක> දෝෂ / අනතුරු ඇඟවීම> අවලංගු කරන ලද සහ සීමා කරන ලද API කට්ටලය තහනම් යොමු (ප්‍රවේශ නීති) "අනතුරු ඇඟවීම" ".
මයිකල් ඇන්ඩර්සන්

43

මට මගේ පිළිතුර මෙතැනින් පිටපත් කළ හැකිය: ජාවා හි මතකය කාන්දු වීමට පහසුම ක්‍රමය?

"පරිගණක විද්‍යාවේ (හෝ කාන්දු වීම, මෙම සන්දර්භය තුළ) මතක කාන්දුවක් සිදුවන්නේ පරිගණක වැඩසටහනක් මතකය පරිභෝජනය කරන නමුත් එය නැවත මෙහෙයුම් පද්ධතියට මුදා හැරීමට නොහැකි වූ විටය." (විකිපීඩියා)

පහසුම පිළිතුර: ඔබට බැහැ. ජාවා ස්වයංක්‍රීය මතක කළමනාකරණය කරන අතර ඔබට අවශ්‍ය නොවන සම්පත් නිදහස් කරයි. ඔබට මෙය සිදුවීම වැළැක්විය නොහැක. එය සෑම විටම සම්පත් නිදහස් කිරීමට හැකි වනු ඇත. අතින් මතක කළමනාකරණය සහිත වැඩසටහන් වලදී මෙය වෙනස් වේ. Malloc () භාවිතා කර ඔබට C හි යම් මතකයක් ලබා ගත නොහැක. මතකය නිදහස් කිරීම සඳහා, ඔබට malloc ආපසු පැමිණි දර්ශකය අවශ්‍ය වන අතර ඒ මත නොමිලේ () අමතන්න. නමුත් ඔබට තවදුරටත් දර්ශකය නොමැති නම් (නැවත ලිවීම හෝ ජීවිත කාලය ඉක්මවා), එවිට ඔබට අවාසනාවකට මෙම මතකය නිදහස් කිරීමට නොහැකි වන අතර එමඟින් ඔබට මතක කාන්දුවක් ඇත.

මේ දක්වා ඇති අනෙක් සියලුම පිළිතුරු මගේ අර්ථ දැක්වීමේදී ඇත්ත වශයෙන්ම මතක කාන්දු නොවේ. ඔවුන් සියල්ලන්ම මතකය අර්ථ විරහිත දේවලින් වේගයෙන් පුරවා ගැනීම අරමුණු කරයි. නමුත් ඕනෑම වේලාවක ඔබ විසින් නිර්මාණය කරන ලද වස්තූන් අවලංගු කර මතකය නිදහස් කර ගත හැකිය -> නැත. කසළ එකතු කරන්නාට නිමක් නැති පුඩුවක් තුළට බලහත්කාරයෙන් කඩා වැටීම සඳහා ඔහුගේ විසඳුම effectively ලදායී බැවින් මා පිළිගත යුතු බැවින් ඇකෝන්රාඩ්ගේ පිළිතුර ඉතා සමීප වේ.

දීර් answer පිළිතුර නම්: JNI භාවිතා කර ජාවා සඳහා පුස්තකාලයක් ලිවීමෙන් ඔබට මතක කාන්දුවක් ලබා ගත හැකි අතර එමඟින් අතින් මතක කළමනාකරණය සහ මතක කාන්දු විය හැකිය. ඔබ මෙම පුස්තකාලය අමතන්නේ නම්, ඔබේ ජාවා ක්‍රියාවලිය මතකය කාන්දු වේ. නැතහොත්, ඔබට ජේවීඑම් හි දෝෂ තිබිය හැකිය, එවිට ජේවීඑම් මතකය නැති වේ. ජේවීඑම් හි බොහෝ විට දෝෂ තිබේ, කසළ එකතු කිරීම එතරම් සුළු දෙයක් නොවන නිසා දන්නා සමහරක් ඒවා තිබිය හැකිය, නමුත් එය තවමත් දෝෂයකි. සැලසුම අනුව මෙය කළ නොහැකිය. එවැනි දෝෂයක් මඟින් ක්‍රියාත්මක වන ජාවා කේතයක් ඔබ ඉල්ලා සිටිය හැකිය. කණගාටුයි, මම එකක් නොදන්නා අතර එය කෙසේ හෝ ඊළඟ ජාවා අනුවාදයේ දෝෂයක් නොවනු ඇත.


12
එය මතක කාන්දු වීම පිළිබඳ අතිශය සීමිත (හා එතරම් ප්‍රයෝජනවත් නොවේ) අර්ථ දැක්වීමකි. ප්‍රායෝගික අරමුණු සඳහා අර්ථවත් වන එකම නිර්වචනය වන්නේ "මතක කාන්දු වීමක් යනු වැඩසටහන විසින් එය තබා ඇති දත්ත තවදුරටත් මතකය වෙන් කිරීමෙන් පසුව මතකය දිගටම පවත්වා ගෙන යන ඕනෑම කොන්දේසියකි."
මේසන් රෝද

1
සඳහන් කළ ඇක්‍රොන්රාඩ්ගේ පිළිතුර මකා දමා තිබේද?
ටොමේ සැටෝ - මොනිකා

1
@ ටොම්සැටෝ: නැහැ. මම ඉහත සඳහන දැන් සම්බන්ධ කිරීම සඳහා යොමු කළෙමි, එවිට ඔබට එය පහසුවෙන් සොයාගත හැකිය.
යැන්කි

වස්තු නැවත නැඟිටීම යනු කුමක්ද? විනාශ කරන්නෙකුට කී වතාවක් කතා කරයිද? මෙම ප්‍රශ්න මෙම පිළිතුර සනාථ කරන්නේ කෙසේද?
ඔටිසම්

1
GC නොතකා ඔබට ජාවා තුළ මතක කාන්දුවක් නිර්මාණය කළ හැකි අතර, ඉහත අර්ථ දැක්වීම තවමත් ඉටු කරන්න. වෙනත් කිසිදු කේතයක් ඉවත් නොකරන පරිදි බාහිර ප්‍රවේශයන්ගෙන් ආරක්ෂා කර ඇති උපග්‍රන්ථ පමණක් දත්ත ව්‍යුහයක් තිබිය යුතුය - වැඩසටහනට කේතය නොමැති නිසා මතකය මුදා හැරිය නොහැක.
මෙවලම් සැකසුම්

39

මෙන්න http://wiki.eclipse.org/Performance_Bloopers#String.substring.28.29 හරහා සරල / නපුරු එකක් .

public class StringLeaker
{
    private final String muchSmallerString;

    public StringLeaker()
    {
        // Imagine the whole Declaration of Independence here
        String veryLongString = "We hold these truths to be self-evident...";

        // The substring here maintains a reference to the internal char[]
        // representation of the original string.
        this.muchSmallerString = veryLongString.substring(0, 1);
    }
}

උපස්ථරය මුල්, වඩා දිගු නූල් වල අභ්‍යන්තර නිරූපණයට යොමු වන නිසා, මුල් පිටපත මතකයේ රැඳේ. මේ අනුව, ඔබට ස්ට්‍රිං ලීකර් වාදනය කරන තාක් කල්, ඔබ තනි අක්ෂර මාලාවක් මත රඳවාගෙන සිටින බව ඔබ සිතුවත්, මුළු මුල් නූලම මතකයේ ඇත.

මුල් නූලට අනවශ්‍ය සඳහනක් ගබඩා කිරීමෙන් වළක්වා ගත හැකි ක්‍රමය නම් මේ වගේ දෙයක් කිරීමයි:

...
this.muchSmallerString = new String(veryLongString.substring(0, 1));
...

අමතර නරක සඳහා, ඔබට .intern()උපස්ථරය ද විය හැකිය :

...
this.muchSmallerString = veryLongString.substring(0, 1).intern();
...

එසේ කිරීමෙන් ස්ට්‍රිංලීකර් උදාහරණය ඉවත දැමීමෙන් පසුව පවා මුල් දිගු නූල් සහ ව්‍යුත්පන්න උපස්ථරය මතකයේ රැඳෙනු ඇත.


4
මතක කාන්දුවක් යැයි මම නොකියමි . නිදහස් වූ විට muchSmallerString( StringLeakerවස්තුව විනාශ වන නිසා), දිගු නූල ද නිදහස් වේ. මම මතක කාන්දු වීම ලෙස හඳුන්වන්නේ ජේවීඑම් හි මෙම අවස්ථාවෙහිදී කිසි විටෙකත් නිදහස් කළ නොහැකි මතකයයි. කෙසේ වෙතත්, මතකය නිදහස් කර ගන්නේ කෙසේදැයි ඔබම පෙන්වා ඇත : this.muchSmallerString=new String(this.muchSmallerString). සැබෑ මතක කාන්දුවක් සමඟ, ඔබට කළ හැකි කිසිවක් නැත.
rds

2
dsrds, එය සාධාරණ කරුණකි. නොවන internඅවස්ථාව "මතක කාන්දුවකට" වඩා "මතක විස්මයක්" විය හැකිය. .intern()කෙසේ වෙතත්, උපස්ථරය නිසැකවම දිගු නූලට යොමු කිරීම ආරක්ෂා කර ගත හැකි සහ නිදහස් කළ නොහැකි තත්වයක් නිර්මාණය කරයි.
ජෝන් චේම්බර්ස්

15
උපස්ථර ක්‍රමය () java7 හි නව සංගීතයක් නිර්මාණය කරයි (එය නව හැසිරීමකි)
anstarovoyt

ඔබට උපස්ථරය () ඔබම කිරීමට අවශ්‍ය නැත: විශාල ආදානයක ඉතා කුඩා කොටසකට ගැලපෙන පරිදි රීජෙක්ස් මැචරයක් භාවිතා කර “උපුටා ගත්” නූල දිගු කාලයක් පුරා ගෙන යන්න. දැවැන්ත ආදානය ජාවා 6 දක්වා සජීවීව පවතී.
Bananeweizen

37

GUI කේතයේ මේ සඳහා පොදු උදාහරණයක් වන්නේ විජට් / සංරචකයක් නිර්මාණය කිරීම සහ යම් ස්ථිතික / යෙදුම් විෂය පථයකට සවන්දෙන්නෙකු එක් කිරීම සහ විජට් විනාශ වූ විට සවන්දෙන්නන් ඉවත් නොකිරීම ය. ඔබට මතක කාන්දුවක් ලැබෙනවා පමණක් නොව, ඔබ සිදුවීම් වලට සවන් දෙන ඕනෑම දෙයක්, ඔබේ පැරණි සවන්දෙන්නන් ද කැඳවනු ලැබේ.


1
ඇන්ඩ්‍රොයිඩ් වේදිකාව මඟින් දර්ශනයක ස්ථිතික ක්ෂේත්‍රය තුළ බිට්මැප් හැඹිලියක් මඟින් නිර්මාණය කරන ලද මතක කාන්දුවක් ලබා දේ .
rds

36

ඕනෑම සර්වට් බහාලුමක් තුළ ධාවනය වන ඕනෑම වෙබ් යෙදුමක් ගන්න (ටොම්කාට්, ජැටි, ග්ලාස්ෆිෂ්, ඕනෑම දෙයක් ...). යෙදුම නැවත වරක් 10 හෝ 20 වතාවක් නැවත යෙදවීම (සේවාදායකයේ ස්වයංක්‍රීය ඩිරෙක්ටරියේ WAR ස්පර්ශ කිරීමට එය ප්‍රමාණවත් විය හැකිය.

කිසිවෙකු මෙය සත්‍ය වශයෙන්ම අත්හදා බලා නොමැති නම්, නැවත සේවයේ යෙදවීමෙන් පසු ඔබට OutOfMemoryError එකක් ලැබීමට ඇති ඉඩකඩ වැඩිය, මන්ද යෙදුම පසුව පිරිසිදු කිරීමට සැලකිලිමත් නොවූ බැවිනි. මෙම පරීක්ෂණය සමඟ ඔබේ සේවාදායකයේ දෝෂයක් පවා ඔබට සොයාගත හැකිය.

ගැටළුව වන්නේ, කන්ටේනරයේ ආයු කාලය ඔබේ යෙදුමේ ආයු කාලය වඩා දිගු වීමයි. ඔබේ යෙදුමේ වස්තූන් හෝ පංති සඳහා කන්ටේනරයට තිබිය හැකි සියලු යොමු කිරීම් කුණු එකතු කළ හැකි බවට ඔබ වග බලා ගත යුතුය.

ඔබගේ වෙබ් යෙදුමේ un න සේවා නියුක්තියෙන් නොනැසී පවතින්නේ එක් සඳහනක් නම්, අනුරූප පංති භාරකරු සහ එහි ප්‍රති ence ලයක් ලෙස ඔබේ වෙබ් යෙදුමේ සියලුම පංති කුණු එකතු කළ නොහැක.

ඔබගේ යෙදුම මඟින් ආරම්භ කරන ලද නූල්, ThreadLocal විචල්‍යයන්, ල ging ු-සටහන් එකතු කරන්නන් පන්ති භාරකරුවන්ගේ කාන්දුවීම් ඇති කරන සාමාන්‍ය සැකකරුවන් වේ.


1
මෙය මතක කාන්දුවක් නිසා නොව, පංති භාරකරු පෙර පන්ති කට්ටලය මුදා නොහරින බැවිනි. එම නිසා සේවාදායකය නැවත ආරම්භ නොකර යෙදුම් සේවාදායකයක් නැවත යෙදවීම නිර්දේශ නොකරයි (භෞතික යන්ත්‍රය නොව යෙදුම් සේවාදායකය). මම වෙබ්ස්පියර් සමඟ එකම ගැටලුව දැක ඇත්තෙමි.
ස්වේන්

35

සමහර විට JNI හරහා බාහිර ස්වදේශීය කේතය භාවිතා කිරීමෙන්ද?

පිරිසිදු ජාවා සමඟ, එය පාහේ කළ නොහැකි ය.

නමුත් එය "සම්මත" ආකාරයේ මතක කාන්දුවක් ගැන වන අතර, ඔබට තවදුරටත් මතකයට ප්‍රවේශ විය නොහැකි නමුත් එය තවමත් යෙදුමට අයත් වේ. ඔබට ඒ වෙනුවට භාවිතයට නොගත් වස්තූන් වෙත යොමු කිරීම් තබා ගත හැකිය, නැතහොත් ඒවා වසා නොගෙන ධාරාවන් විවෘත කරන්න.


22
එය "මතක කාන්දු" යන්නෙහි අර්ථ දැක්වීම මත රඳා පවතී. "මතකය රඳවාගෙන ඇති නමුත් තවදුරටත් අවශ්‍ය නොවේ" නම්, ජාවා හි එය කිරීම පහසුය. එය "මතකය වෙන් කර ඇති නමුත් කේතයට කිසිසේත් ප්‍රවේශ විය නොහැක" නම්, එය තරමක් අපහසු වේ.
ජෝකිම් සෝවර්

O ජෝකිම් සෝවර් - මම අදහස් කළේ දෙවන වර්ගයයි. පළමුවැන්න සෑදීම පහසුය :)
Rogach

6
"පිරිසිදු ජාවා සමඟ, එය පාහේ කළ නොහැකි ය." හොඳයි, මගේ අත්දැකීම් තවත් එකක් වන්නේ මෙහි ඇති අන්තරායන් ගැන නොදන්නා අය විසින් හැඹිලි ක්‍රියාත්මක කිරීමේදී ය.
ෆේබියන් බාර්නි

4
Og රොගාච්: +10 000 නියෝජිතයින් සිටින විවිධ පිළිතුරු සඳහා මූලික වශයෙන් +400 ඉහළ නැංවීම් ඇති බව පෙන්නුම් කරන්නේ අවස්ථා දෙකේදීම ජොකිම් සෝවර් අදහස් දක්වමින් එය කළ හැකි බවයි. එබැවින් ඔබගේ "පාහේ කළ නොහැක්කක්" තේරුමක් නැත.
SyntaxT3rr0r

32

PermGen සහ XML විග්‍රහ කිරීම සම්බන්ධයෙන් මට එක් වරක් “මතක කාන්දුවක්” තිබේ. සංසන්දනය වේගවත් කිරීම සඳහා අප භාවිතා කළ එක්ස්එම්එල් විග්‍රහකය (එය කුමක්දැයි මට මතක නැත) ටැග් නම් මත String.intern () කළා. අපගේ ගනුදෙනුකරුවකුට දත්ත අගයන් එක්ස්එම්එල් ගුණාංග හෝ පෙළෙහි නොව ටැග් නම් ලෙස ගබඩා කිරීමට හොඳ අදහසක් තිබුණි, එබැවින් අපට මෙවැනි ලේඛනයක් තිබේ:

<data>
   <1>bla</1>
   <2>foo</>
   ...
</data>

ඇත්ත වශයෙන්ම, ඔවුන් සංඛ්‍යා භාවිතා නොකළ නමුත් දිගු පෙළ හැඳුනුම්පත් (අක්ෂර 20 ක් පමණ) අද්විතීය වූ අතර ඒවා දිනකට මිලියන 10-15 අතර අනුපාතයකින් පැමිණියේය. එමඟින් දිනකට මෙගාබයිට් 200 ක් කුණු බවට පත් වන අතර එය නැවත කිසි විටෙකත් අවශ්‍ය නොවන අතර කිසි විටෙකත් ජී.සී.ඩී. (එය පර්ම්ජෙන් හි ඇති බැවින්). අපට පර්මජන් 512 MB ලෙස සකසා ඇති අතර, ඒ නිසා මතකයෙන් බැහැරව (OOME) පැමිණීමට දින දෙකක් පමණ ගත විය ...


4
ඔබේ උදාහරණ කේතය නිට්පික් කිරීම සඳහා: XML හි මූලද්‍රව්‍ය නම් ලෙස අංක (හෝ සංඛ්‍යා වලින් ආරම්භ වන නූල්) ඉඩ නොදේ.
Paŭlo Ebermann

JDK 7+ සඳහා මෙය තවදුරටත් සත්‍ය නොවන බව සලකන්න. සවිස්තරාත්මක ලිවීම සඳහා මෙම ලිපිය බලන්න: java-performance.info/string-intern-in-java-6-7-8
jmiserez

ඉතින්, මම හිතන්නේ String වෙනුවට StringBuffer භාවිතා කිරීමෙන් මෙම ගැටළුව විසඳෙනු ඇත? ඒක නැද්ද?
anubhs

24

මතක කාන්දුවක් යනු කුමක්ද:

  • එය දෝෂයක් නිසා හෝ නරක සැලසුමක් .
  • එය මතකය නාස්තියකි.
  • කාලයත් සමඟ එය නරක අතට හැරේ.
  • කසළ එකතු කරන්නාට එය පිරිසිදු කළ නොහැක.

සාමාන්‍ය උදාහරණය:

වස්තු හැඹිලිය යනු දේවල් අවුල් කිරීමට හොඳ ආරම්භයකි.

private static final Map<String, Info> myCache = new HashMap<>();

public void getInfo(String key)
{
    // uses cache
    Info info = myCache.get(key);
    if (info != null) return info;

    // if it's not in cache, then fetch it from the database
    info = Database.fetch(key);
    if (info == null) return null;

    // and store it in the cache
    myCache.put(key, info);
    return info;
}

ඔබේ හැඹිලිය වැඩී වර්ධනය වේ. ඉතා ඉක්මණින් මුළු දත්ත සමුදායම මතකයට නංවනු ඇත. වඩා හොඳ සැලසුමක් LRUMap භාවිතා කරයි (මෑතකදී භාවිතා කළ වස්තු හැඹිලියේ තබා ගනී).

නිසැකවම, ඔබට දේවල් වඩාත් සංකීර්ණ කළ හැකිය:

  • ThreadLocal භාවිතා කිරීම ඉදිකිරීම් කිරීම.
  • වඩාත් සංකීර්ණ යොමු ගස් එකතු කිරීම .
  • හෝ තෙවන පාර්ශවීය පුස්තකාල නිසා සිදුවන කාන්දුවීම් .

බොහෝ විට සිදුවන්නේ කුමක්ද:

මෙම තොරතුරු වස්තුවට වෙනත් වස්තූන් වෙත යොමු කිරීම් තිබේ නම්, එය නැවත වෙනත් වස්තූන් වෙත යොමු කරයි. එක්තරා ආකාරයකින් ඔබට මෙය යම් ආකාරයක මතක කාන්දුවක් ලෙස සැලකිය හැකිය (නරක සැලසුම නිසා).


22

කිසිවෙකු අභ්‍යන්තර පන්තියේ උදාහරණ භාවිතා නොකිරීම සිත්ගන්නා සුළු යැයි මම සිතුවෙමි. ඔබට අභ්යන්තර පංතියක් තිබේ නම්; එය සහජයෙන්ම අඩංගු පන්තියට යොමු කිරීමක් පවත්වා ගනී. ඇත්ත වශයෙන්ම එය තාක්‍ෂණිකව මතක කාන්දුවක් නොවේ, මන්ද ජාවා අවසානයේ එය පිරිසිදු කරයි; නමුත් මෙය පංති බලාපොරොත්තු වූවාට වඩා දිගු කාලයක් රැඳී සිටීමට හේතු වේ.

public class Example1 {
  public Example2 getNewExample2() {
    return this.new Example2();
  }
  public class Example2 {
    public Example2() {}
  }
}

දැන් ඔබ නිදර්ශන 1 අමතා නිදර්ශන 1 ඉවතලමින් නිදර්ශන 2 ලබා ගන්නේ නම්, ඔබට සහජයෙන්ම නිදර්ශන 1 වස්තුවකට සබැඳියක් ඇත.

public class Referencer {
  public static Example2 GetAnExample2() {
    Example1 ex = new Example1();
    return ex.getNewExample2();
  }

  public static void main(String[] args) {
    Example2 ex = Referencer.GetAnExample2();
    // As long as ex is reachable; Example1 will always remain in memory.
  }
}

ඔබට නිශ්චිත කාලයකට වඩා වැඩි කාලයක් විචල්‍යයක් තිබේ නම් කටකතාවක් මා අසා ඇත; ජාවා උපකල්පනය කරන්නේ එය සැමවිටම පවතිනු ඇති අතර කේතයෙන් තවදුරටත් ළඟා විය නොහැකි නම් එය කිසි විටෙකත් පිරිසිදු කිරීමට උත්සාහ නොකරනු ඇති බවයි. නමුත් එය සම්පූර්ණයෙන්ම තහවුරු කර නොමැත.


2
අභ්‍යන්තර පංති කලාතුරකින් ගැටළුවක් වේ. ඒවා case ජු නඩුවක් වන අතර හඳුනා ගැනීමට ඉතා පහසුය. කටකතාව ද කටකතාවක් පමණි.
bestsss

2
"කටකතාව" හරියට පරම්පරාගත GC ක්‍රියා කරන ආකාරය ගැන යමෙකු අඩක් කියවා ඇති බවක් පෙනේ. දිගු කලක් ජීවත් වූ නමුත් දැන් ළඟා විය නොහැකි වස්තූන් සැබවින්ම රැඳී සිටිමින් ටික වේලාවක් ඉඩ ලබා ගත හැකිය, මන්ද ජේවීඑම් තරුණ පරම්පරාවෙන් ඒවා ප්‍රවර්ධනය කළ නිසා සෑම පාස් එකක්ම පරීක්ෂා කිරීම නතර කළ හැකිය. ඔවුන් සැලසුම් කර ඇති පරිදි "මගේ තාවකාලික නූල් 5000 පිරිසිදු කරන්න" යන පාස් මග හරිනු ඇත. නමුත් ඔවුන් අමරණීය නොවේ. ඔවුන් තවමත් එකතු කිරීම සඳහා සුදුසුකම් ලබා ඇති අතර, VM RAM සඳහා පටවා ඇත්නම්, එය අවසානයේදී සම්පූර්ණ GC අතුගා දැමීමක් සිදු කර එම මතකය නැවත ලබා ගනී.
cHao

22

Log4j මගින් යම් ආකාරයකින් මතකය කාන්දු වීමේ තත්වයක් මට මෑතකදී හමු විය.

Log4j හි මෙම යාන්ත්‍රණය Nested Diagnostic Context (NDC) ලෙස හැඳින්වේ ලෙස නම් කර ඇති අතර එය විවිධ ප්‍රභවයන්ගෙන් අන්තර් සම්බන්ධිත ලොග් ප්‍රතිදානය වෙන්කර හඳුනා ගැනීමේ මෙවලමකි. එන්ඩීසී වැඩ කරන කැටිති බව නූල් වේ, එබැවින් එය විවිධ නූල් වලින් ලොග් ප්‍රතිදානයන් වෙන වෙනම වෙන් කරයි.

නූල් විශේෂිත ටැග් ගබඩා කිරීම සඳහා, log4j හි NDC පන්තිය විසින් නූල් වස්තුව විසින්ම යතුරු ලියනය කරන ලද හැෂ් ටේබල් එකක් භාවිතා කරයි (නූල් හැඳුනුම්පත යැයි පැවසීමට වඩා වෙනස්ව), එබැවින් එන්ඩීසී ටැගය මතකයේ රැඳෙන තුරු නූල් වලින් එල්ලෙන සියලුම වස්තු වස්තුව ද මතකයේ රැඳේ. අපගේ වෙබ් යෙදුම තුළ, එක් ඉල්ලීමකින් ල logs ු-සටහන් වෙන් වෙන් වශයෙන් වෙන්කර හඳුනා ගැනීම සඳහා ඉල්ලීම් හැඳුනුම්පතක් සමඟ ලොග්අවුට් ටැග් කිරීමට අපි එන්ඩීසී භාවිතා කරමු. එන්ඩීසී ටැගය නූල් සමඟ සම්බන්ධ කරන කන්ටේනරය, ඉල්ලීමකින් ප්‍රතිචාරය ලබා දෙන අතරතුර එය ඉවත් කරයි. ඉල්ලීමක් සැකසීමේදී ළමා නූලක් බිහි වූ විට පහත සඳහන් කේතය වැනි දෙයක් ඇතිවිය.

pubclic class RequestProcessor {
    private static final Logger logger = Logger.getLogger(RequestProcessor.class);
    public void doSomething()  {
        ....
        final List<String> hugeList = new ArrayList<String>(10000);
        new Thread() {
           public void run() {
               logger.info("Child thread spawned")
               for(String s:hugeList) {
                   ....
               }
           }
        }.start();
    }
}    

එබැවින් එන්ඩීසී සන්දර්භයක් බිහි වූ පේළිගත නූල් සමඟ සම්බන්ධ විය. මෙම එන්ඩීසී සන්දර්භය සඳහා යතුර වූ නූල් වස්තුව, දැවැන්ත ලැයිස්තුගත වස්තුව එහි එල්ලී ඇති පේළිගත නූල් වේ. එම නිසා නූල් එය කරමින් සිටි දේ අවසන් කිරීමෙන් පසුව පවා, දැවැන්ත ලැයිස්තුව පිළිබඳ සඳහන එන්ඩීසී සන්දර්භය හේස්ටබල් විසින් සජීවීව තබා ඇති අතර එමඟින් මතක කාන්දු වීමක් සිදුවිය.


එය උරා බොයි. ගොනුවකට පිවිසීමේදී ZERO මතකය වෙන් කරන මෙම ල ging ු
TraderJoeChicago

+1 එම්ඩීසී සමඟ slf4j / logback (එකම කතුවරයාගේ අනුප්‍රාප්තික නිෂ්පාදන) හා සමාන ගැටළුවක් තිබේද යන්න ඔබ දන්නවාද? මම මූලාශ්‍රය ගැන ගැඹුරට කිමිදීමට සූදානම් නමුත් පළමුව පරීක්ෂා කිරීමට අවශ්‍ය විය. කෙසේ හෝ මෙය පළ කිරීම ගැන ස්තූතියි.
sparc_spread

20

සම්මුඛ පරීක්‍ෂකවරයා බොහෝ විට පහත කේතය වැනි චක්‍රලේඛ යොමු කිරීමක් සොයමින් සිටියේය (අහම්බෙන් යොමු ගණනය කිරීම් භාවිතා කළ ඉතා පැරණි ජේවීඑම් වල මතකය පමණක් කාන්දු වන අතර එය තවදුරටත් එසේ නොවේ). නමුත් එය ඉතා අපැහැදිලි ප්‍රශ්නයකි, එබැවින් ජේවීඑම් මතක කළමනාකරණය පිළිබඳ ඔබේ අවබෝධය පෙන්වීමට මෙය ප්‍රධාන අවස්ථාවකි.

class A {
    B bRef;
}

class B {
    A aRef;
}

public class Main {
    public static void main(String args[]) {
        A myA = new A();
        B myB = new B();
        myA.bRef = myB;
        myB.aRef = myA;
        myA=null;
        myB=null;
        /* at this point, there is no access to the myA and myB objects, */
        /* even though both objects still have active references. */
    } /* main */
}

එවිට ඔබට යොමු ගණනය කිරීම් සමඟ ඉහත කේතය මතකය කාන්දු වන බව පැහැදිලි කළ හැකිය. නමුත් බොහෝ නූතන ජේවීඑම් යන්ත්‍ර තවදුරටත් යොමු ගණන් කිරීම භාවිතා නොකරයි, බොහෝ දෙනා ස්වීප් කසළ එකතු කරන්නෙකු භාවිතා කරයි, ඇත්ත වශයෙන්ම මෙම මතකය එකතු කරනු ඇත.

මීළඟට ඔබට මෙවැනි ස්වදේශීය සම්පතක් ඇති වස්තුවක් නිර්මාණය කිරීම පැහැදිලි කළ හැකිය:

public class Main {
    public static void main(String args[]) {
        Socket s = new Socket(InetAddress.getByName("google.com"),80);
        s=null;
        /* at this point, because you didn't close the socket properly, */
        /* you have a leak of a native descriptor, which uses memory. */
    }
}

එවිට ඔබට මෙය තාක්‍ෂණිකව මතක කාන්දුවක් බව පැහැදිලි කළ හැකිය, නමුත් ඇත්ත වශයෙන්ම කාන්දුව සිදුවන්නේ ජේවීඑම් හි ස්වදේශීය කේතය නිසා ඔබේ ජාවා කේතය මඟින් නිදහස් නොවූ යටින් පවතින දේශීය සම්පත් වෙන් කිරීමෙනි.

දවස අවසානයේදී, නවීන ජේවීඑම් සමඟ, ඔබ ජේවීඑම් දැනුවත් කිරීමේ සාමාන්‍ය විෂය පථයෙන් පිටත දේශීය සම්පතක් වෙන් කරන ජාවා කේත කිහිපයක් ලිවිය යුතුය.


19

ස්වදේශික කේත මාර්ගය සෑම කෙනෙකුටම සැමවිටම අමතක වේ. කාන්දු වීම සඳහා සරල සූත්‍රයක් මෙන්න:

  1. ස්වදේශීය ක්‍රමය ප්‍රකාශ කරන්න.
  2. ස්වදේශීය ක්‍රමයේදී අමතන්න malloc. අමතන්න එපා free.
  3. ස්වදේශීය ක්‍රමය අමතන්න.

මතක තබා ගන්න, ස්වදේශීය කේතයේ මතක වෙන් කිරීම් පැමිණෙන්නේ ජේවීඑම් ගොඩවලිනි.


1
සත්‍ය කතාවක් පදනම් කරගෙන.
Reg

18

ස්ථිතික සිතියමක් සාදන්න සහ ඒ සඳහා දැඩි යොමු කිරීම් එකතු කරන්න. ඒවා කිසි විටෙකත් GC'd නොවනු ඇත.

public class Leaker {
    private static final Map<String, Object> CACHE = new HashMap<String, Object>();

    // Keep adding until failure.
    public static void addToCache(String key, Object value) { Leaker.CACHE.put(key, value); }
}

87
එය කාන්දුවක් වන්නේ කෙසේද? එය කරන්නේ ඔබ ඉල්ලන දේමයි. එය කාන්දුවක් නම්, ඕනෑම තැනක වස්තු නිර්මාණය කිරීම හා ගබඩා කිරීම කාන්දුවකි.
ෆල්මාරි

3
මම al ෆල්මාරි සමඟ එකඟ වෙමි. මට එහි කාන්දුවක් නොපෙනේ, ඔබ වස්තු නිර්මාණය කරමින් සිටී. 'RemoveFromCache' නමින් වෙනත් ක්‍රමයක් සමඟ ඔබ වෙන් කළ මතකය නිසැකවම නැවත ලබා ගත හැකිය. කාන්දුවක් යනු ඔබට මතකය නැවත ලබා ගත නොහැකි වූ විටය.
කයිල්

3
මගේ අදහස නම්, වස්තූන් නිර්මාණය කිරීම දිගටම කරගෙන යන, සමහර විට ඒවා හැඹිලියකට දැමීමෙන්, ඔවුන් පරිස්සම් නොවන්නේ නම් OOM දෝෂයක් ඇතිවිය හැකිය.
duffymo

8
uff ඩෆිමෝ: නමුත් ඇත්ත වශයෙන්ම ප්‍රශ්නය අසන්නේ එය නොවේ. ඔබේ සියලු මතකය සරලව භාවිතා කිරීම සමඟ එයට කිසිදු සම්බන්ධයක් නැත.
ෆල්මාරි

3
නියත වශයෙන්ම අවලංගුය. ඔබ සිතියම් එකතුවක වස්තු පොකුරක් එකතු කරමින් සිටී. සිතියම ඒවා තබා ඇති නිසා ඔවුන්ගේ යොමු කිරීම් තබා ගනු ඇත.
gyorgyabraham

16

එම පන්තියේ අවසාන ක්‍රමයේදී පන්තියක නව අවස්ථාවක් නිර්මාණය කිරීමෙන් ඔබට චලනය වන මතක කාන්දුවක් නිර්මාණය කළ හැකිය. අවසාන කාරකය අවස්ථා කිහිපයක් නිර්මාණය කරන්නේ නම් ප්‍රසාද ලකුණු. ඔබේ ගොඩවල ප්‍රමාණය අනුව තත්පර කිහිපයකින් සහ මිනිත්තු කිහිපයකින් මුළු ගොඩවල්ම කාන්දු වන සරල වැඩසටහනක් මෙන්න:

class Leakee {
    public void check() {
        if (depth > 2) {
            Leaker.done();
        }
    }
    private int depth;
    public Leakee(int d) {
        depth = d;
    }
    protected void finalize() {
        new Leakee(depth + 1).check();
        new Leakee(depth + 1).check();
    }
}

public class Leaker {
    private static boolean makeMore = true;
    public static void done() {
        makeMore = false;
    }
    public static void main(String[] args) throws InterruptedException {
        // make a bunch of them until the garbage collector gets active
        while (makeMore) {
            new Leakee(0).check();
        }
        // sit back and watch the finalizers chew through memory
        while (true) {
            Thread.sleep(1000);
            System.out.println("memory=" +
                    Runtime.getRuntime().freeMemory() + " / " +
                    Runtime.getRuntime().totalMemory());
        }
    }
}

15

කිසිවෙකු තවම මෙය පවසා ඇතැයි මම නොසිතමි: අවසාන () ක්‍රමය ඉක්මවා යාමෙන් ඔබට වස්තුවක් නැවත නැඟිටුවිය හැකිය. කසළ එකතු කරන්නා වස්තුව මත එක් වරක් පමණක් කැඳවනු ලබන අතර එමඟින් වස්තුව කිසි විටෙකත් විනාශ නොවනු ඇත.


10
මෙය අසත්‍යයකි. finalize()කැඳවනු නොලැබේ, නමුත් වැඩි යොමු කිරීම් නොමැති විට වස්තුව එකතු කරනු ලැබේ. කසළ එකතු කරන්නා 'කැඳවනු නොලැබේ'.
bestsss

1
මෙම පිළිතුර නොමඟ යවන සුළුය, මෙම finalize()ක්‍රමය හැඳින්විය හැක්කේ එක් වරක් පමණක් ජේවීඑම් ය, නමුත් මින් අදහස් කරන්නේ එම වස්තුව නැවත නැඟිටුවනු ලැබ නැවත කුණු කසළ එකතු කළ නොහැකි බවයි. finalize()ක්‍රමයේ සම්පත් වැසීමේ කේතයක් තිබේ නම් මෙම කේතය නැවත ක්‍රියාත්මක නොවනු ඇත, මෙය මතක කාන්දු වීමට හේතු විය හැක.
ටොම් කැමමන්

15

මෑතකදී මට වඩාත් සියුම් ආකාරයේ සම්පත් කාන්දුවක් හමු විය. අපි පන්ති භාරකරුගේ getResourceAsStream හරහා සම්පත් විවෘත කරන අතර ආදාන ප්‍රවාහ හැසිරවීම් වසා නොතිබුණි.

අහ්, ඔයා කියන්න පුළුවන් මොන මෝඩයෙක්ද කියලා.

හොඳයි, මෙය සිත්ගන්නාසුලු දෙයක් වන්නේ: මේ ආකාරයෙන්, ඔබට ජේවීඑම් හි සංචයට වඩා යටින් පවතින ක්‍රියාවලියේ මතක ශක්තිය කාන්දු විය හැකිය.

ඔබට අවශ්‍ය වන්නේ ජාවා කේතයෙන් යොමු කෙරෙන ගොනුවක් සහිත භාජන ගොනුවක් පමණි. භාජන ගොනුව විශාල වන තරමට මතකය වෙන් කරනු ලැබේ.

පහත දැක්වෙන පන්තිය සමඟ ඔබට පහසුවෙන් එවැනි භාජනයක් නිර්මාණය කළ හැකිය:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class BigJarCreator {
    public static void main(String[] args) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("big.jar")));
        zos.putNextEntry(new ZipEntry("resource.txt"));
        zos.write("not too much in here".getBytes());
        zos.closeEntry();
        zos.putNextEntry(new ZipEntry("largeFile.out"));
        for (int i=0 ; i<10000000 ; i++) {
            zos.write((int) (Math.round(Math.random()*100)+20));
        }
        zos.closeEntry();
        zos.close();
    }
}

BigJarCreator.java නම් ගොනුවකට අලවන්න, එය සම්පාදනය කර විධාන රේඛාවෙන් ක්‍රියාත්මක කරන්න:

javac BigJarCreator.java
java -cp . BigJarCreator

Et voilà: ඔබගේ වර්තමාන වැඩ කරන නාමාවලිය තුළ ලිපිගොනු දෙකක් ඇති භාජන ලේඛනාගාරයක් ඔබ සොයා ගනී.

දෙවන පන්තියක් නිර්මාණය කරමු:

public class MemLeak {
    public static void main(String[] args) throws InterruptedException {
        int ITERATIONS=100000;
        for (int i=0 ; i<ITERATIONS ; i++) {
            MemLeak.class.getClassLoader().getResourceAsStream("resource.txt");
        }
        System.out.println("finished creation of streams, now waiting to be killed");

        Thread.sleep(Long.MAX_VALUE);
    }

}

මෙම පංතිය මූලික වශයෙන් කිසිවක් නොකරයි, නමුත් යොමු නොකළ InputStream වස්තු නිර්මාණය කරයි. එම වස්තූන් වහාම එකතු කරනු ලබන කසළ වන අතර එමඟින් ගොඩවල් ප්‍රමාණයට දායක නොවන්න. පවත්නා සම්පතක් භාජන ගොනුවකින් පැටවීම අපගේ උදාහරණයට වැදගත් වන අතර ප්‍රමාණය මෙහි වැදගත් වේ!

ඔබට සැකයක් ඇත්නම්, ඉහත පන්තිය සම්පාදනය කර ආරම්භ කිරීමට උත්සාහ කරන්න, නමුත් හොඳ ගොඩවල් ප්‍රමාණයක් (2 MB) තෝරා ගැනීමට වග බලා ගන්න:

javac MemLeak.java
java -Xmx2m -classpath .:big.jar MemLeak

ඔබට මෙහි OOM දෝෂයක් හමු නොවනු ඇත, කිසිදු සඳහනක් තබා නොමැති බැවින්, ඉහත උදාහරණයේ ඔබ කොතරම් විශාල ITERATIONS තෝරා ගත්තද යෙදුම දිගටම ක්‍රියාත්මක වේ. යෙදුම පොරොත්තු විධානය වෙත ළඟා නොවන්නේ නම් ඔබේ ක්‍රියාවලියේ මතක පරිභෝජනය (ඉහළින් (RES / RSS) හෝ ක්‍රියාවලි ගවේෂකය) වර්ධනය වේ. ඉහත සැකසුම තුළ, එය මතකයේ 150 MB පමණ වෙන් කරනු ඇත.

යෙදුම ආරක්ෂිතව ධාවනය කිරීමට ඔබට අවශ්‍ය නම්, ආදාන ප්‍රවාහය එය නිර්මාණය කළ ස්ථානයේම වසා දමන්න:

MemLeak.class.getClassLoader().getResourceAsStream("resource.txt").close();

ඔබේ ක්‍රියාවලිය පුනරාවර්තන ගණනට වඩා 35 MB නොඉක්මවනු ඇත.

ඉතා සරල හා පුදුම සහගතය.


14

බොහෝ අය යෝජනා කර ඇති පරිදි, සම්පත් කාන්දුවීම් ඇති කිරීම තරමක් පහසුය - ජේඩීබීසී උදාහරණ මෙන්. තථ්‍ය මතක කාන්දුවීම් ටිකක් අමාරුයි - විශේෂයෙන් ඔබ වෙනුවෙන් එය කිරීමට ජේවීඑම් හි බිඳුණු බිටු මත රඳා නොසිටින්නේ නම් ...

ඉතා විශාල අඩිපාරක් ඇති වස්තූන් නිර්මාණය කර පසුව ඒවාට ප්‍රවේශ වීමට නොහැකි වීම සැබෑ මතක කාන්දු නොවේ. කිසිවක් වෙත පිවිසිය නොහැකි නම් එය කසළ එකතු වනු ඇත, යම් දෙයකට එයට පිවිසිය හැකි නම් එය කාන්දුවක් නොවේ ...

කෙසේ වෙතත් වැඩ කිරීමට භාවිතා කළ එක් ක්‍රමයක් - සහ එය තවමත් පවතීදැයි මම නොදනිමි - ගැඹුරු තුනක වටකුරු දාමයක් තිබීම. වස්තුවෙහි A වස්තුවට යොමු දැක්වීමක් ඇති පරිදි, වස්තුව B ට වස්තුව C හා වස්තුව C වෙත වස්තුව A සඳහා යොමු දැක්වීමක් ඇත. ගැඹුරු දාම දෙකක් - A <--> B හි මෙන් දැන ගැනීමට GC දක්ෂ විය. - A සහ ​​B වෙනත් කිසිවක් වෙත ප්‍රවේශ විය නොහැකි නමුත් ආරක්ෂිතව ත්‍රිවිධ දාමය හැසිරවිය නොහැකි නම් ආරක්ෂිතව එකතු කර ගත හැකිය ...


7
කලක සිට එසේ නොවේ. නූතන GCs රවුම් යොමු කිරීම් හැසිරවිය යුතු ආකාරය දනී.
assylias

13

විශාල මතක කාන්දුවීම් ඇති කළ හැකි තවත් ක්‍රමයක් Map.Entry<K,V>නම් aTreeMap .

මෙය TreeMaps ට පමණක් අදාළ වන්නේ මන්දැයි උපකල්පනය කිරීම දුෂ්කර ය, නමුත් ක්‍රියාත්මක කිරීම දෙස බැලීමෙන් හේතුව එය විය හැකිය: TreeMap.Entryගබඩාවක් එහි සහෝදර සහෝදරියන් ගැන සඳහන් කරයි, එබැවින් TreeMapඑකතු කිරීමට සුදානම් නම් , නමුත් වෙනත් පංතියක් ඕනෑම එකක් ගැන සඳහනක් දරයි එය Map.Entry, එවිට මුළු සිතියම මතකයේ රැඳෙනු ඇත.


සැබෑ ජීවිතයේ තත්වය:

විශාල TreeMapදත්ත ව්‍යුහයක් ලබා දෙන db විමසුමක් තිබීම ගැන සිතා බලන්න . TreeMapමූලද්‍රව්‍ය ඇතුළත් කිරීමේ අනුපිළිවෙල රඳවා තබා ඇති බැවින් මිනිසුන් සාමාන්‍යයෙන් s භාවිතා කරයි .

public static Map<String, Integer> pseudoQueryDatabase();

විමසුම බොහෝ වාර ගණනක් කැඳවනු ලැබුවහොත් සහ එක් එක් විමසුම සඳහා (එසේ නම්, Mapආපසු පැමිණි සෑම කෙනෙකුටම ) ඔබ Entryකොතැනක හෝ ඉතිරි කළහොත්, මතකය නිරන්තරයෙන් වර්ධනය වේ.

පහත සඳහන් ආවරණ පන්තිය සලකා බලන්න:

class EntryHolder {
    Map.Entry<String, Integer> entry;

    EntryHolder(Map.Entry<String, Integer> entry) {
        this.entry = entry;
    }
}

අයදුම්පත:

public class LeakTest {

    private final List<EntryHolder> holdersCache = new ArrayList<>();
    private static final int MAP_SIZE = 100_000;

    public void run() {
        // create 500 entries each holding a reference to an Entry of a TreeMap
        IntStream.range(0, 500).forEach(value -> {
            // create map
            final Map<String, Integer> map = pseudoQueryDatabase();

            final int index = new Random().nextInt(MAP_SIZE);

            // get random entry from map
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                if (entry.getValue().equals(index)) {
                    holdersCache.add(new EntryHolder(entry));
                    break;
                }
            }
            // to observe behavior in visualvm
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

    }

    public static Map<String, Integer> pseudoQueryDatabase() {
        final Map<String, Integer> map = new TreeMap<>();
        IntStream.range(0, MAP_SIZE).forEach(i -> map.put(String.valueOf(i), i));
        return map;
    }

    public static void main(String[] args) throws Exception {
        new LeakTest().run();
    }
}

සෑම pseudoQueryDatabase()ඇමතුමකටම පසු , mapඅවස්ථා එකතු කිරීමට සූදානම් විය යුතුය, නමුත් එය සිදු නොවේ, අවම වශයෙන් එකක් Entryවෙනත් තැනක ගබඩා කර ඇති බැවින්.

ඔබගේ jvmසැකසීම් මත පදනම්ව , යෙදුම මුල් අවධියේදී බිඳ වැටීමට ඉඩ ඇත OutOfMemoryError.

visualvmමතකය වර්ධනය වන ආකාරය මෙම ප්‍රස්ථාරයෙන් ඔබට දැක ගත හැකිය .

මතක ඩම්ප් - ට්‍රීමැප්

හැෂ් කළ දත්ත ව්‍යුහයක් ( HashMap) සමඟ එය සිදු නොවේ .

A භාවිතා කරන විට මෙය ප්‍රස්ථාරයයි HashMap.

මතක ඩම්ප් - හැෂ්මැප්

විසඳුම? සුරැකීමට වඩා යතුර / අගය කෙලින්ම සුරකින්න (ඔබ දැනටමත් කර ඇති පරිදි) Map.Entry.


මම මෙහි වඩාත් පුළුල් මිණුම් ලකුණක් ලියා ඇත .


11

නූල් අවසන් වන තුරු එකතු නොකෙරේ. ඒවා කසළ එකතු කිරීමේ මූලයන් ලෙස සේවය කරයි . ඒවා හුදෙක් ඒවා ගැන අමතක කිරීමෙන් හෝ ඒවා වෙත යොමු කිරීම් ඉවත් කිරීමෙන් නැවත ලබා ගත නොහැකි වස්තු කිහිපයෙන් එකකි.

සලකා බලන්න: සේවක නූල් අවසන් කිරීම සඳහා මූලික රටාව වන්නේ නූල් දකින යම් තත්ව විචල්‍යයක් සැකසීමයි. නූල් මඟින් වරින් වර විචල්‍යය පරීක්ෂා කර එය අවසන් කිරීමට සං signal ාවක් ලෙස භාවිතා කළ හැකිය. විචල්‍යය ප්‍රකාශයට පත් නොකළේ නම්, විචල්‍යයේ volatileවෙනස නූල් මඟින් නොපෙනේ, එබැවින් එය අවසන් කිරීමට නොදැනේ. නැතහොත් සමහර නූල් වලට හවුල් වස්තුවක් යාවත්කාලීන කිරීමට අවශ්‍ය දැයි සිතන්න, නමුත් එය අගුළු දැමීමට උත්සාහ කරන අතරතුර අවහිර කරන්න.

ඔබ සතුව ඇත්තේ නූල් අතලොස්සක් නම්, මෙම දෝෂ බොහෝ විට පැහැදිලි වනු ඇත්තේ ඔබේ වැඩසටහන නිසි ලෙස ක්‍රියා කිරීම නවත්වන බැවිනි. ඔබට අවශ්‍ය පරිදි තවත් නූල් නිර්මාණය කරන නූල් තටාකයක් තිබේ නම්, යල්පැනගිය / සිරවී ඇති නූල් නොපෙනී යා හැකි අතර, එය දින නියමයක් නොමැතිව එකතු වී මතක කාන්දු වීමට හේතු වේ. නූල් ඔබේ යෙදුමේ වෙනත් දත්ත භාවිතා කිරීමට ඉඩ ඇත, එම නිසා ඔවුන් කෙලින්ම සඳහන් කරන කිසිවක් එකතු කිරීම වලක්වනු ඇත.

සෙල්ලම් උදාහරණයක් ලෙස:

static void leakMe(final Object object) {
    new Thread() {
        public void run() {
            Object o = object;
            for (;;) {
                try {
                    sleep(Long.MAX_VALUE);
                } catch (InterruptedException e) {}
            }
        }
    }.start();
}

System.gc()ඔබ කැමති සියල්ල අමතන්න , නමුත් සම්මත කළ වස්තුව leakMeකිසි විටෙකත් මිය යන්නේ නැත.

(* සංස්කරණය කරන ලදි *)


1
P ස්පීඩි කිසිවක් "හිරවී" නැත. ඇමතුම් ක්‍රමය ක්ෂණිකව නැවත පැමිණෙන අතර සම්මත වස්තුව නැවත ගොඩගනු නොලැබේ. එය හරියටම කාන්දුවකි.
බෝවන්

1
ඔබේ වැඩසටහනේ ජීවිත කාලය පුරාම ඔබට “ධාවනය” (හෝ නිදාගැනීම, ඕනෑම දෙයක්) ඇත. එය මට කාන්දුවක් ලෙස ගණන් නොගනී. ඔබ තටාකයක් මුළුමනින්ම භාවිතා නොකළත්, කාන්දුවක් ලෙස ගණන් නොගනී.
ස්පයිඩි

1
P ස්පීඩි "ඔබේ වැඩසටහනේ ජීවිත කාලය පුරාම ඔබට [දෙයක්] ලැබෙනු ඇත. එය මට කාන්දුවක් ලෙස ගණන් නොගනී." ඔබට ඔබම ඇසෙනවාද?
බෝවන්

3
@Spidey ක්‍රියාවලිය කාන්දු නොවන බව ඔබ මතකය ගණනය කරන්නේ නම්, මෙහි ඇති සියලුම පිළිතුරු වැරදියි, මන්ද ක්‍රියාවලිය සැමවිටම එහි අථත්‍ය ලිපින අවකාශයේ කුමන පිටු සිතියම් ගත කර ඇත්දැයි සොයා බලයි. ක්‍රියාවලිය අවසන් වූ විට, මෙහෙයුම් පද්ධතිය විසින් සියලු කාන්දුවීම් නිදහස් පිටු පිටුපසට තැබීමෙන් පිරිසිදු කරයි. එය ඊළඟ අන්තයට ගෙන යාම සඳහා, RAM චිපවල හෝ තැටියේ ඇති swap අවකාශයේ ඇති භෞතික බිටු කිසිවක් භෞතිකව අස්ථානගත වී හෝ විනාශ වී නොමැති බව පෙන්වා දීමෙන් ඕනෑම තර්ක කාන්දුවකට පහර දිය හැකිය. එවිට ඔබට පරිගණකය ක්‍රියා විරහිත කළ හැකිය ඕනෑම කාන්දුවක් පිරිසිදු කිරීමට නැවත.
බෝවන්

1
කාන්දුවක ප්‍රායෝගික අර්ථ දැක්වීම නම්, එය අප නොදන්නා නිසා මතකය නැතිවී ගොස් ඇති අතර එමඟින් එය නැවත ලබා ගැනීමට අවශ්‍ය ක්‍රියා පටිපාටිය කළ නොහැකි ය; අපට සිදුවන්නේ සමස්ත මතක අවකාශය ඉරා දමා නැවත ගොඩනඟා ගැනීමයි. මේ වගේ රළු නූල් ස්වභාවිකව මාරාන්තික හෝ මෝඩ නූල් පූල් ක්‍රියාත්මක කිරීම තුළින් මතු විය හැකිය. එවැනි නූල් මගින් යොමු කරන ලද වස්තූන්, වක්‍රව පවා එකතු කිරීම වලක්වා ඇත, එබැවින් අපට මතකය ඇති අතර එමඟින් වැඩසටහනේ ජීවිත කාලය තුළ ස්වභාවිකව ගොඩකර ගැනීමට හෝ නැවත භාවිතා කිරීමට නොහැකි වනු ඇත. මම එය ගැටලුවක් ලෙස හඳුන්වන්නෙමි; විශේෂයෙන් එය මතක කාන්දුවකි.
බෝවන්

10

වලංගු නිදසුනක් වනුයේ නූල් සංචිත කර ඇති පරිසරයක ThreadLocal විචල්‍යයන් භාවිතා කිරීමයි.

නිදසුනක් ලෙස, වෙනත් වෙබ් සංරචක සමඟ සන්නිවේදනය කිරීම සඳහා සර්ව්ලෙට්ස් හි ThreadLocal විචල්‍යයන් භාවිතා කිරීම, කන්ටේනරය මඟින් නූල් සාදනු ලැබීම සහ අක්‍රීය ඒවා තටාකයක පවත්වා ගැනීම. ThreadLocal විචල්‍යයන්, නිවැරදිව පිරිසිදු නොකළ හොත්, එකම වෙබ් සංරචකය ඒවායේ අගයන් නැවත ලියන තුරු එහි ජීවත් වේ.

ඇත්ත වශයෙන්ම, හඳුනාගත් පසු, ගැටළුව පහසුවෙන් විසඳා ගත හැකිය.


10

සම්මුඛ පරීක්ෂක රවුම් යොමු විසඳුමක් සොයමින් සිටින්නට ඇත:

    public static void main(String[] args) {
        while (true) {
            Element first = new Element();
            first.next = new Element();
            first.next.next = first;
        }
    }

මෙය කුණු එකතු කරන්නන් යොමු කිරීමේ සම්භාව්‍ය ගැටළුවකි. මෙම සීමාව නොමැති වඩාත් නවීන ඇල්ගොරිතමයක් ජේවීඑම් භාවිතා කරන බව ඔබ ආචාරශීලීව පැහැදිලි කරනු ඇත.

-වෙස් ටාර්ල්


12
මෙය කුණු එකතු කරන්නන් යොමු කිරීමේ සම්භාව්‍ය ගැටළුවකි. අවුරුදු 15 කට පෙර පවා ජාවා ref ගණන් කිරීම භාවිතා කළේ නැත. Ref. ගණනය කිරීම ද GC ට වඩා මන්දගාමී වේ.
bestsss

4
මතක කාන්දුවක් නොවේ. අනන්ත පුඩුවක් පමණි.
එස්බන් ස්කොව් පෙඩර්සන්

2
S එස්බන් එක් එක් පුනරාවර්තනයේදී, පෙර firstඒවා ප්‍රයෝජනවත් නොවන අතර කසළ එකතු කළ යුතුය. දී සඳහන් ඡන්ද ගණන් කිරීමේ කසළ එකතු, එය පිළිබඳ ක්රියාශීලී සඳහනක් (ම විසින්) ඇති නිසා වස්තුව freeed කළ නොහැකි වනු ඇත. කාන්දුව අවලංගු කිරීම සඳහා අනන්ත පුඩුවක් මෙහි ඇත: ඔබ වැඩසටහන ක්‍රියාත්මක කරන විට, මතකය දින නියමයක් නොමැතිව ඉහළ යනු ඇත.
rds

dsrds @ වෙස්ලි ටාර්ල් සිතන්නේ ලූපය අසීමිත නොවන බවයි. තවමත් මතක කාන්දුවක් තිබේද?
nz_21
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.