हाय!

मला वाटते की तुमच्या कॉम्प्युटरमध्ये मर्यादित मेमरी आहे हे मी तुम्हाला सांगितल्यास तुम्हाला फारसे आश्चर्य वाटणार नाही :) अगदी हार्ड ड्राइव्ह — साधारणत: RAM स्टोरेजपेक्षा कितीतरी पटीने मोठी — तुमच्या आवडत्या गेम, टीव्ही शो, सह क्षमतेनुसार पॅक केली जाऊ शकते. आणि अधिक. हे होण्यापासून रोखण्यासाठी, तुम्हाला मेमरीच्या सद्य स्थितीचे निरीक्षण करणे आणि तुमच्या संगणकावरून अनावश्यक फाइल्स हटवणे आवश्यक आहे. जावा प्रोग्रामिंगचा या सगळ्याशी काय संबंध? सर्व काही! शेवटी, जेव्हा Java मशीन कोणतीही वस्तू तयार करते, तेव्हा ते त्या वस्तूसाठी मेमरी वाटप करते.

वास्तविक मोठ्या प्रोग्राममध्ये, दहापट आणि शेकडो हजारो वस्तू तयार केल्या जातात आणि त्या प्रत्येकाची स्वतःची मेमरी असते. पण या सर्व वस्तू किती काळ अस्तित्वात आहेत असे तुम्हाला वाटते? आमचा कार्यक्रम चालू असताना ते "लाइव्ह" असतात का? नक्कीच नाही. जावा ऑब्जेक्ट्सचे सर्व फायदे असूनही, ते अमर नाहीत :) ऑब्जेक्ट्सचे स्वतःचे जीवनचक्र असते. आज आम्ही कोड लिहिण्यापासून थोडा ब्रेक घेऊ आणि ही प्रक्रिया पाहू :) शिवाय, प्रोग्राम कसा कार्य करतो आणि संसाधने कशी व्यवस्थापित केली जातात हे समजून घेण्यासाठी हे खूप महत्वाचे आहे. तर, वस्तूचे जीवन कधी सुरू होते? एखाद्या व्यक्तीप्रमाणे - त्याच्या जन्मापासून, म्हणजेच निर्मिती.


Cat cat = new Cat(); // Here the lifecycle of our Cat object begins!

प्रथम, जावा व्हर्च्युअल मशीन ऑब्जेक्ट तयार करण्यासाठी आवश्यक प्रमाणात मेमरीचे वाटप करते. मग त्या स्मृतीचा संदर्भ तयार होतो. आमच्या बाबतीत, तो संदर्भ म्हणतात cat, त्यामुळे आम्ही त्याचा मागोवा ठेवू शकतो. मग त्याचे सर्व व्हेरिएबल्स इनिशियलाइज केले जातात, कन्स्ट्रक्टरला कॉल केला जातो आणि — ta-da! - आमची नव्याने तयार झालेली वस्तू स्वतःचे जीवन जगत आहे :)

वस्तूंचे आयुर्मान बदलते, म्हणून आम्ही येथे अचूक संख्या देऊ शकत नाही. कोणत्याही परिस्थितीत, तो प्रोग्राममध्ये काही काळ राहतो आणि त्याचे कार्य करतो. तंतोतंत सांगायचे तर, एखादी वस्तू "जिवंत" असते जोपर्यंत त्याचे संदर्भ असतात. कोणतेही संदर्भ शिल्लक नसल्यामुळे, वस्तू "मृत्यू" होते. उदाहरण:


public class Car {
  
   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");
       lamborghini = null;

   }

}

लॅम्बोर्गिनी डायब्लो कार ऑब्जेक्ट पद्धतीच्या दुसऱ्या ओळीवर जिवंत होणे थांबवते main(). त्यात फक्त एकच संदर्भ होता, आणि नंतर तो संदर्भ समान सेट केला गेला null. लॅम्बोर्गिनी डायब्लोचे कोणतेही संदर्भ शिल्लक नसल्यामुळे, वाटप केलेली मेमरी "कचरा" बनते. हे होण्यासाठी संदर्भ शून्य वर सेट करणे आवश्यक नाही:


public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");

       Car lamborghiniGallardo = new Car("Lamborghini Gallardo");
       lamborghini = lamborghiniGallardo;
   }

}

येथे आपण दुसरा ऑब्जेक्ट तयार केला आणि नंतर हा नवीन ऑब्जेक्ट संदर्भासाठी नियुक्त केला lamborghini. आता Lamborghini Gallardoऑब्जेक्टला दोन संदर्भ आहेत, परंतु Lamborghini Diabloऑब्जेक्टला एकही नाही. म्हणजे ती Diabloवस्तू आता कचरा झाली आहे. जेव्हा जावा ची अंगभूत यंत्रणा ज्याला गार्बेज कलेक्टर (GC) म्हणतात ते कार्यात येते.

कचरा संकलक ही एक अंतर्गत जावा यंत्रणा आहे जी मेमरी मुक्त करण्यासाठी जबाबदार आहे, म्हणजे मेमरीमधून अनावश्यक वस्तू काढून टाकणे. आम्ही येथे रोबोट व्हॅक्यूम क्लिनरचे चित्र निवडण्याचे एक चांगले कारण आहे. शेवटी, कचरा गोळा करणारा त्याच प्रकारे कार्य करतो: पार्श्वभूमीत, तो आपल्या प्रोग्रामबद्दल "प्रवास" करतो, आपल्या भागावर कोणतेही प्रयत्न न करता कचरा गोळा करतो. प्रोग्राममध्ये वापरल्या जाणार्‍या वस्तू काढून टाकणे हे त्याचे कार्य आहे.

असे केल्याने संगणकातील मेमरी इतर वस्तूंसाठी मोकळी होते. तुम्हाला आठवत असेल की धड्याच्या सुरुवातीला आम्ही सांगितले होते की सामान्य जीवनात तुम्हाला तुमच्या संगणकाच्या स्थितीचे निरीक्षण करावे लागेल आणि अनावश्यक फाइल्स हटवाव्या लागतील? बरं, जावा ऑब्जेक्ट्सच्या बाबतीत, कचरा गोळा करणारा तुमच्यासाठी हे करतो. तुमचा प्रोग्राम चालू असताना कचरा गोळा करणारा वारंवार चालतो: हे तांत्रिकदृष्ट्या शक्य असले तरी, तुम्हाला स्पष्टपणे कॉल करण्याची किंवा कमांड देण्याची गरज नाही. नंतर आम्ही याबद्दल अधिक बोलू आणि त्याच्या कार्याचे अधिक तपशीलवार विश्लेषण करू.

जेव्हा कचरा गोळा करणारा एखाद्या वस्तूवर पोहोचतो, तेव्हा ती वस्तू नष्ट करण्याआधी, तो finalize()ऑब्जेक्टवर एक विशेष पद्धत — — कॉल करतो. ही पद्धत ऑब्जेक्टद्वारे वापरलेली इतर संसाधने सोडू शकते. पद्धत finalize()वर्गाचा भाग आहे Object. याचा अर्थ असा की तुम्ही पूर्वी भेटलेल्या equals(), hashCode()आणि toString()पद्धतींव्यतिरिक्त, प्रत्येक ऑब्जेक्टमध्ये ही पद्धत आहे. हे इतर पद्धतींपेक्षा वेगळे आहे की ते - मी हे कसे ठेवले पाहिजे - खूप लहरी.

विशेषतः, एखाद्या वस्तूचा नाश होण्याआधी ते नेहमी म्हटले जात नाही. प्रोग्रामिंग हा एक अचूक प्रयत्न आहे. प्रोग्रामर संगणकाला काहीतरी करायला सांगतो आणि संगणक ते करतो. मला असे वाटते की तुम्हाला या वर्तनाची आधीच सवय झाली आहे, म्हणून प्रथम तुम्हाला ही खालील कल्पना स्वीकारणे कठीण होऊ शकते: "वस्तूंचा नाश करण्यापूर्वी, वर्गाची पद्धत कॉल केली जाते. finalize()किंवा Objectकदाचित ती कॉल केली जात नाही. हे सर्व यावर अवलंबून असते तुझे नशीब!"

तरीही, ते खरे आहे. finalize()केस-बाय-केस आधारावर पद्धत कॉल करायची की नाही हे Java मशीन स्वतः ठरवते . उदाहरणार्थ, प्रयोग म्हणून खालील कोड चालवण्याचा प्रयत्न करूया:


public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public Cat() {
   }

   public static void main(String[] args) throws Throwable {
       for (int i = 0 ; i < 1000000; i++) {
           Cat cat = new Cat();
           cat = null; // This is when the first object becomes available to the garbage collector
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Cat object destroyed!");
   }
}

आपण एक Catऑब्जेक्ट तयार करतो आणि नंतर कोडच्या पुढील ओळीत आपण त्याचा एकमेव संदर्भ शून्य बरोबर सेट करतो. आणि आम्ही ते लाखो वेळा करतो. आम्ही finalize()पद्धत स्पष्टपणे ओव्हररॉड केली जेणेकरून ती कन्सोलवर एक दशलक्ष वेळा स्ट्रिंग मुद्रित करेल (प्रत्येक वेळी ती एखादी Catवस्तू नष्ट करेल). पण नाही! तंतोतंत सांगायचे तर, ते माझ्या संगणकावर फक्त 37,346 वेळा चालले! म्हणजेच, माझ्या मशीनवर स्थापित केलेल्या जावा मशीनने 27 पैकी एकदाच finalize()पद्धत कॉल करण्याचा निर्णय घेतला.

इतर प्रकरणांमध्ये, त्याशिवाय कचरा उचलला गेला. हा कोड स्वतःसाठी चालवण्याचा प्रयत्न करा: बहुधा, तुम्हाला वेगळा परिणाम मिळेल. जसे तुम्ही बघू शकता, finalize()क्वचितच एक विश्वासार्ह भागीदार म्हटले जाऊ शकते :) म्हणून, भविष्यासाठी एक छोटासा सल्ला: finalize()गंभीर संसाधने मुक्त करण्याच्या पद्धतीवर अवलंबून राहू नका. कदाचित JVM त्याला कॉल करेल, किंवा कदाचित नाही. कुणास ठाऊक?

तुमचा ऑब्जेक्ट जिवंत असताना त्याच्याकडे काही संसाधने असतील जी कार्यक्षमतेसाठी अत्यंत महत्त्वाची आहेत, उदाहरणार्थ, एक ओपन डेटाबेस कनेक्शन, ते सोडण्यासाठी तुमच्या वर्गात एक विशेष पद्धत तयार करणे चांगले आहे आणि नंतर ऑब्जेक्ट नसताना स्पष्टपणे कॉल करा. आवश्यक अशा प्रकारे तुम्हाला खात्री आहे की तुमच्या प्रोग्रामच्या कार्यक्षमतेला त्रास होणार नाही. सुरुवातीपासूनच, आम्ही म्हणालो की स्मृतीसह कार्य करणे आणि कचरा काढून टाकणे खूप महत्वाचे आहे, आणि हे खरे आहे. अयोग्यरित्या संसाधने हाताळणे आणि अनावश्यक वस्तू कशा साफ केल्या जातात याचा गैरसमज यामुळे मेमरी लीक होऊ शकते. ही सर्वात प्रसिद्ध प्रोग्रामिंग चुकांपैकी एक आहे.

जर प्रोग्रामरने त्यांचा कोड चुकीचा लिहिला तर, प्रत्येक वेळी नवीन तयार केलेल्या वस्तूंसाठी नवीन मेमरी वाटप केली जाऊ शकते, तर जुन्या, अनावश्यक वस्तू कचरा गोळा करणाऱ्याद्वारे काढण्यासाठी उपलब्ध नसतील. आम्ही रोबोट व्हॅक्यूम क्लिनरशी साधर्म्य बनवल्यामुळे, रोबोट सुरू करण्यापूर्वी, तुम्ही घराभोवती मोजे विखुरले, काचेची फुलदाणी फोडली आणि मजल्यावरील लेगो बिल्डिंग ब्लॉक्स सोडल्यास काय होईल याची कल्पना करा. रोबोट नक्कीच त्याचे काम करण्याचा प्रयत्न करेल, परंतु कधीतरी तो अडकेल.

रोबोट व्हॅक्यूम क्लिनरला योग्यरित्या कार्य करण्यास अनुमती देण्यासाठी, तुम्हाला मजला चांगल्या स्थितीत ठेवण्याची आणि रोबोट हाताळू शकत नसलेली कोणतीही गोष्ट काढून टाकणे आवश्यक आहे. हेच तत्व Java च्या कचरा गोळा करणाऱ्याला लागू होते. जर एखाद्या प्रोग्राममध्ये अनेक वस्तू उरल्या असतील ज्या साफ केल्या जाऊ शकत नाहीत (जसे की आमच्या रोबोट व्हॅक्यूम क्लिनरसाठी सॉक किंवा लेगो बिल्डिंग ब्लॉक), काही क्षणी तुमची मेमरी संपेल. आणि तो फक्त तुमचा प्रोग्राम नसू शकतो जो फ्रीज होईल — संगणकावर चालणारा प्रत्येक इतर प्रोग्राम प्रभावित होऊ शकतो. त्यांच्याकडेही पुरेशी स्मृती नसावी.

तुम्हाला हे लक्षात ठेवण्याची गरज नाही. ते कसे कार्य करते त्यामागील तत्त्व समजून घेणे आवश्यक आहे.