CodeGym /Java Blog /यादृच्छिक /जावा मध्ये फॅंटम संदर्भ
John Squirrels
पातळी 41
San Francisco

जावा मध्ये फॅंटम संदर्भ

यादृच्छिक या ग्रुपमध्ये प्रकाशित केले
हाय! आजच्या चर्चेत आपण जावा मधील "फँटम रेफरन्सेस" (फँटम रेफरन्स) बद्दल सविस्तर बोलू. हे कोणत्या प्रकारचे संदर्भ आहेत? त्यांना "फँटम रेफरन्स" का म्हणतात? ते कसे वापरले जातात? तुम्हाला आठवत असेल, Java मध्ये 4 प्रकारचे संदर्भ आहेत:
  1. StrongReference (ऑब्जेक्ट तयार करताना आपण तयार करतो ते सामान्य संदर्भ):

    Cat cat = new Cat()

    या उदाहरणात, मांजर एक मजबूत संदर्भ आहे.

  2. SoftReference (सॉफ्ट रेफरन्स). आमच्याकडे अशा संदर्भांचा धडा होता.

  3. WeakReference (कमकुवत संदर्भ). येथे त्यांच्याबद्दल एक धडा देखील होता .

  4. PhantomReference (फॅंटम संदर्भ).

शेवटचे तीन प्रकार पॅरामीटर्ससह जेनेरिक प्रकार आहेत (उदाहरणार्थ, SoftReference<Integer> , WeakReference<MyClass> ). SoftReference , WeakReference , आणि PhantomReference वर्ग संदर्भ वर्गातून वारशाने मिळतात . या वर्गांसह काम करताना सर्वात महत्वाच्या पद्धती आहेत:
  • get() — संदर्भित ऑब्जेक्ट परत करते;

  • clear() — ऑब्जेक्टचा संदर्भ काढून टाकते.

SoftReference आणि WeakReference वरील धड्यांमधून तुम्हाला या पद्धती आठवतात . हे लक्षात ठेवणे महत्त्वाचे आहे की ते वेगवेगळ्या प्रकारच्या संदर्भांसह वेगळ्या पद्धतीने कार्य करतात. आज आपण पहिल्या तीन प्रकारांमध्ये डुबकी मारणार नाही. त्याऐवजी, आम्ही फॅन्टम संदर्भांबद्दल बोलू. आम्ही इतर प्रकारच्या संदर्भांना स्पर्श करू, परंतु केवळ ते फॅंटम संदर्भांपेक्षा कसे वेगळे आहेत या संदर्भात. चल जाऊया! :) सुरुवातीला, आपल्याला फॅन्टम संदर्भांची अजिबात गरज का आहे? तुम्हाला माहिती आहे की, कचरा संग्राहक (gc) अनावश्यक Java वस्तूंद्वारे वापरलेली मेमरी रिलीझ करतो. कलेक्टर दोन "पास" मध्ये ऑब्जेक्ट हटवतो. पहिल्या पासमध्ये, ते फक्त वस्तू पाहते आणि आवश्यक असल्यास, त्यांना "अनावश्यक" म्हणून चिन्हांकित करते (म्हणजे, "हटवायचे"). जरfinalize()ऑब्जेक्टसाठी पद्धत ओव्हरराइड केली गेली आहे, त्याला म्हणतात. किंवा कदाचित ते म्हटले जात नाही - हे सर्व केवळ आपण भाग्यवान आहात की नाही यावर अवलंबून आहे. तुम्हाला कदाचित आठवत असेल की ते finalize()चंचल आहे :) कचरा गोळा करणाऱ्याच्या दुसऱ्या पासमध्ये, ऑब्जेक्ट हटवला जातो आणि मेमरी मुक्त केली जाते. कचरा वेचणार्‍यांच्या अप्रत्याशित वागणुकीमुळे आमच्यासाठी अनेक समस्या निर्माण होतात. कचरा उचलण्याचे काम नेमके केव्हा सुरू होईल, हे कळत नाही. finalize()पद्धत कॉल केली जाईल की नाही हे आम्हाला माहित नाही . शिवाय, ऑब्जेक्टची finalize()पद्धत अंमलात आणली जात असताना त्याचा एक मजबूत संदर्भ तयार केला जाऊ शकतो, अशा परिस्थितीत ऑब्जेक्ट हटविला जाणार नाही. उपलब्ध मेमरीवर जास्त मागणी करणार्‍या प्रोग्रामसाठी, हे सहजपणे होऊ शकते OutOfMemoryError. हे सर्व आपल्याला फॅन्टम संदर्भ वापरण्यास प्रवृत्त करते. वस्तुस्थिती अशी आहे की यामुळे कचरा वेचणाऱ्याच्या वागण्यात बदल होतो. जर ऑब्जेक्टमध्ये फक्त फॅन्टम संदर्भ असतील तर:
  • त्याची finalize() पद्धत म्हणतात (जर ती अधिलिखित केली असेल)

  • Finalize() पद्धत पूर्ण झाल्यावर काहीही बदलले नाही आणि ऑब्जेक्ट अजूनही हटवला जाऊ शकतो, तर ऑब्जेक्टचा फॅन्टम संदर्भ एका विशेष रांगेत ठेवला जातो: ReferenceQueue .

फॅंटम संदर्भांसह कार्य करताना समजून घेणे सर्वात महत्वाची गोष्ट म्हणजे ऑब्जेक्टचा फॅंटम संदर्भ या रांगेत येईपर्यंत मेमरीमधून हटविला जात नाही. फँटम रेफरन्सवर क्लिअर() पद्धत कॉल केल्यावरच ते हटवले जाईल . एक उदाहरण पाहू. प्रथम, आम्ही एक चाचणी वर्ग तयार करू जो काही प्रकारचा डेटा संचयित करेल.

public class TestClass {
   private StringBuffer data;
   public TestClass() {
       this.data = new StringBuffer();
       for (long i = 0; i < 50000000; i++) {
           this.data.append('x');
       }
   }
   @Override
   protected void finalize() {
       System.out.println("The finalize method has been called on the TestClass object");
   }
}
जेव्हा आम्ही वस्तू तयार करतो, तेव्हा अधिक मेमरी घेण्यासाठी आम्ही त्यांना हेतुपुरस्सर एक मोठा "भार" (प्रत्येक ऑब्जेक्टमध्ये 50 दशलक्ष "x" वर्ण जोडून) देऊ. या व्यतिरिक्त, ती रन झाली आहे हे पाहण्यासाठी आम्ही finalize() पद्धत ओव्हरराइड करतो. पुढे, आम्हाला PhantomReference कडून वारसा मिळेल अशा वर्गाची आवश्यकता आहे . आम्हाला अशा वर्गाची गरज का आहे? हे सर्व सरळ आहे. हे आम्हाला स्पष्ट () पद्धतीमध्ये अतिरिक्त तर्क जोडण्यास अनुमती देईल जेणेकरून फॅंटम संदर्भ खरोखर साफ झाला आहे (ज्याचा अर्थ ऑब्जेक्ट हटविला गेला आहे).

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class MyPhantomReference<TestClass> extends PhantomReference<TestClass> {

   public MyPhantomReference(TestClass obj, ReferenceQueue<TestClass> queue) {

       super(obj, queue);

       Thread thread = new QueueReadingThread<TestClass>(queue);

       thread.start();
   }

   public void cleanup() {
       System.out.println("Cleaning up a phantom reference! Removing an object from memory!");
       clear();
   }
}
पुढे, आम्हाला एका वेगळ्या धाग्याची आवश्यकता आहे जो कचरा गोळा करणार्‍याचे काम करण्यासाठी प्रतीक्षा करेल आणि आमच्या संदर्भपंक्तीत फॅंटम लिंक्स दिसतील . रांगेत असा संदर्भ संपताच, त्यावर क्लीनअप() पद्धत कॉल केली जाते:

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;

public class QueueReadingThread<TestClass> extends Thread {

   private ReferenceQueue<TestClass> referenceQueue;

   public QueueReadingThread(ReferenceQueue<TestClass> referenceQueue) {
       this.referenceQueue = referenceQueue;
   }

   @Override
   public void run() {

       System.out.println("The thread monitoring the queue has started!");
       Reference ref = null;

       // Wait until the references appear in the queue
       while ((ref = referenceQueue.poll()) == null) {

           try {
               Thread.sleep(50);
           }

           catch (InterruptedException e) {
               throw new RuntimeException("Thread " + getName() + " was interrupted!");
           }
       }

       // As soon as a phantom reference appears in the queue, clean it up
       ((MyPhantomReference) ref).cleanup();
   }
}
आणि शेवटी, आपल्याला main() पद्धतीची आवश्यकता आहे, जी आपण त्यास वेगळ्या मुख्य वर्गात ठेवू . त्या पद्धतीमध्ये, आम्ही एक TestClass ऑब्जेक्ट, त्याचा एक फॅंटम संदर्भ आणि फॅंटम संदर्भांसाठी एक रांग तयार करू. त्यानंतर, आम्ही कचरा गोळा करणाऱ्याला कॉल करू आणि काय होते ते पाहू :)

import java.lang.ref.*;

public class Main {

   public static void main(String[] args) throws InterruptedException {
       Thread.sleep(10000);

       ReferenceQueue<TestClass> queue = new ReferenceQueue<>();
       Reference ref = new MyPhantomReference<>(new TestClass(), queue);

       System.out.println("ref = " + ref);

       Thread.sleep(5000);

       System.out.println("Collecting garbage!");

       System.gc();
       Thread.sleep(300);

       System.out.println("ref = " + ref);

       Thread.sleep(5000);

       System.out.println("Collecting garbage!");

       System.gc();
   }
}
कन्सोल आउटपुट:

ref = MyPhantomReference@4554617c 
The thread monitoring the queue has started! 
Collecting garbage! 
The finalize method has been called on the TestClass object 
ref = MyPhantomReference@4554617c 
Collecting garbage! 
Cleaning up a phantom reference! 
Removing an object from memory! 
आम्ही येथे काय पाहतो? आम्ही ठरवल्याप्रमाणे सर्व काही घडले! आमच्या ऑब्जेक्टची finalize() पद्धत ओव्हरराइड केली आहे आणि कचरा गोळा करणारे चालू असताना कॉल केले गेले. पुढे, फॅंटम संदर्भ संदर्भ रांगेत ठेवला गेला . तेथे असताना, तिची स्पष्ट() पद्धत कॉल केली गेली (ज्यामध्ये आम्ही कन्सोलवर आउटपुट करण्यासाठी क्लीनअप() म्हटले). शेवटी, ऑब्जेक्ट मेमरीमधून हटविला गेला. आता हे नक्की कसे कार्य करते ते तुम्ही पहा :) अर्थात, तुम्हाला फॅंटम संदर्भांबद्दलचे सर्व सिद्धांत लक्षात ठेवण्याची गरज नाही. परंतु किमान मुख्य मुद्दे लक्षात ठेवल्यास चांगले होईल. प्रथम, हे सर्व सर्वात कमकुवत संदर्भ आहेत. जेव्हा वस्तूचे इतर कोणतेही संदर्भ शिल्लक नसतात तेव्हाच ते कार्यात येतात. आम्ही वर दिलेल्या संदर्भांची यादी सर्वात मजबूत ते सर्वात कमकुवत अशा उतरत्या क्रमाने क्रमवारी लावली आहे: मजबूत संदर्भ -> सॉफ्टरेफरन्स -> कमजोर संदर्भ -> फॅंटमरेफरन्स फँटम संदर्भ केवळ तेव्हाच लढाईत प्रवेश करतो जेव्हा आमच्या ऑब्जेक्टसाठी कोणतेही मजबूत, मऊ किंवा कमकुवत संदर्भ नसतात: ) दुसरे, get() पद्धत फॅंटम संदर्भासाठी नेहमी शून्य देते . येथे एक साधे उदाहरण आहे जेथे आम्ही तीन वेगवेगळ्या प्रकारच्या कारसाठी तीन भिन्न प्रकारचे संदर्भ तयार करतो:

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       HybridAuto hybrid = new HybridAuto();
       F1Car f1car = new F1Car();

       SoftReference<Sedan> softReference = new SoftReference<>(sedan);
       System.out.println(softReference.get());

       WeakReference<HybridAuto> weakReference = new WeakReference<>(hybrid);
       System.out.println(weakReference.get());
      
       ReferenceQueue<F1Car> referenceQueue = new ReferenceQueue<>();

       PhantomReference<F1Car> phantomReference = new PhantomReference<>(f1car, referenceQueue);
       System.out.println(phantomReference.get());

   }
}
कन्सोल आउटपुट:

Sedan@4554617c
HybridAuto@74a14482 
null
get () पद्धतीने मऊ आणि कमकुवत संदर्भांसाठी संपूर्णपणे सामान्य वस्तू परत केल्या, परंतु ते फॅंटम संदर्भासाठी शून्य परत केले. तिसरे, फॅंटम संदर्भ मुख्यतः मेमरीमधून वस्तू हटविण्याच्या क्लिष्ट प्रक्रियेमध्ये वापरले जातात. बस एवढेच! :) आज आपला धडा संपतो. परंतु आपण एकट्या सिद्धांतावर फार पुढे जाऊ शकत नाही, म्हणून कार्य सोडवण्याकडे परत जाण्याची वेळ आली आहे! :)
टिप्पण्या
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION