CodeGym /จาวาบล็อก /สุ่ม /วงจรชีวิตของวัตถุ
John Squirrels
ระดับ
San Francisco

วงจรชีวิตของวัตถุ

เผยแพร่ในกลุ่ม
สวัสดี! ฉันคิดว่าคุณคงไม่แปลกใจถ้าฉันบอกคุณว่าคอมพิวเตอร์ของคุณมีหน่วยความจำจำกัด :)
วงจรชีวิตของวัตถุ - 1
แม้แต่ฮาร์ดไดรฟ์ของคุณ (ซึ่งมีขนาดใหญ่กว่า RAM หลายเท่า) ก็ยังเต็มไปด้วยเกมโปรด รายการทีวี และสิ่งอื่นๆ ได้ เพื่อป้องกันไม่ให้สิ่งนี้เกิดขึ้น คุณต้องตรวจสอบสถานะปัจจุบันของหน่วยความจำของคอมพิวเตอร์และลบไฟล์ที่ไม่จำเป็นออก ทั้งหมดนี้เกี่ยวข้องกับการเขียนโปรแกรม Java อย่างไร อย่างตรงไปตรงมา! ท้ายที่สุดแล้วการสร้างวัตถุใด ๆ จะทำให้เครื่อง Java จัดสรรหน่วยความจำให้กับมัน โปรแกรมขนาดใหญ่ในโลกแห่งความเป็นจริงสร้างอ็อบเจกต์หลายหมื่นหรือแสนออบเจกต์ และจัดสรรหน่วยความจำก้อนหนึ่งสำหรับแต่ละออบเจกต์ แต่คุณคิดว่ามีวัตถุเหล่านี้อยู่กี่ชิ้น? พวกเขา "มีชีวิตอยู่" ตลอดเวลาที่โปรแกรมของเรากำลังทำงานอยู่หรือไม่? ไม่แน่นอน แม้จะมีข้อดีทั้งหมด แต่วัตถุ Java ก็ไม่ได้เป็นอมตะ :) วัตถุมีวงจรชีวิตของตัวเอง วันนี้เราจะหยุดพักจากการเขียนโค้ดและสำรวจขั้นตอนนี้กันสักหน่อย :) นอกจากนี้ยังสำคัญมากสำหรับการทำความเข้าใจวิธีการทำงานของโปรแกรมและสำหรับการจัดการทรัพยากร แล้วชีวิตของวัตถุจะเริ่มต้นขึ้นที่ไหน? เหมือนมนุษย์ตั้งแต่แรกเกิด กล่าวคือ เมื่อสร้างแล้ว.

Cat cat = new Cat();// Our Cat object's lifecycle begins now!
ขั้นแรก เครื่องเสมือน Java จะจัดสรรหน่วยความจำที่จำเป็นในการสร้างวัตถุ จากนั้นจะสร้างการอ้างอิงถึงมัน (ในกรณีของเราcat) เพื่อให้สามารถติดตามได้ จากนั้นตัวแปรทั้งหมดจะถูกเตรียมใช้งาน ตัวสร้างถูกเรียกใช้ และออบเจกต์ใหม่ของเรากำลังมีชีวิตของมันเอง :) อายุการใช้งานออบเจกต์จะแตกต่างกันไป ไม่มีตัวเลขที่แน่นอนที่นี่ ไม่ว่าในกรณีใดก็ตาม วัตถุจะอาศัยอยู่ในโปรแกรมและทำหน้าที่ของมันในช่วงระยะเวลาหนึ่ง เพื่อให้แม่นยำ วัตถุนั้น "มีชีวิต" ตราบใดที่มีการอ้างอิงถึงวัตถุนั้น ทันทีที่ไม่มีการอ้างอิง วัตถุ "ตาย" ตัวอย่างเช่น:

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()วิธีการนี้ วัตถุรถยนต์ "Lamborghini Diablo" จะหยุดอยู่ในบรรทัดที่สอง มีการอ้างอิงเพียงรายการเดียว และการอ้างอิงถูกตั้งค่าเป็นโมฆะ เนื่องจากไม่มีการอ้างอิงถึง Diablo เหลืออยู่ จึงกลายเป็น "ขยะ" การอ้างอิงไม่จำเป็นต้องตั้งค่าเป็นศูนย์เพื่อให้สิ่งนี้เกิดขึ้น:

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วัตถุกลายเป็นขยะ นี่คือเมื่อ ตัวรวบรวมขยะในตัวของ Java (GC) เริ่มทำงาน
วงจรชีวิตของวัตถุ - 2
ตัวรวบรวมขยะเป็นกลไก Java ภายในที่รับผิดชอบในการเพิ่มหน่วยความจำ เช่น การลบวัตถุที่ไม่จำเป็นออกจากหน่วยความจำ มีเหตุผลที่เราเลือกที่จะนำเสนอด้วยหุ่นยนต์ดูดฝุ่น ตัวรวบรวมขยะทำงานในลักษณะเดียวกัน: มัน "ย้าย" โปรแกรมของคุณในพื้นหลัง รวบรวมขยะ คุณไม่จำเป็นต้องโต้ตอบกับมัน หน้าที่ของมันคือลบวัตถุที่ไม่ได้ใช้ในโปรแกรมแล้ว ดังนั้นจึงเพิ่มหน่วยความจำให้กับวัตถุอื่น คุณจำได้ไหมว่าในตอนต้นของบทเรียนเรากล่าวว่าในชีวิตจริงคุณต้องตรวจสอบสถานะของคอมพิวเตอร์และลบไฟล์เก่า หากเรากำลังพูดถึงวัตถุ Java ตัวรวบรวมขยะจะทำสิ่งนี้ให้คุณ. ตัวรวบรวมขยะจะเริ่มทำงานหลายครั้งในขณะที่โปรแกรมของคุณทำงาน: คุณไม่จำเป็นต้องเรียกใช้และออกคำสั่งอย่างชัดเจน (แม้ว่าจะเป็นไปได้ในทางเทคนิค) เราจะพูดถึงตัวเก็บขยะเพิ่มเติมในภายหลังและวิเคราะห์วิธีการทำงานอย่างละเอียด เมื่อตัวเก็บขยะไปถึงวัตถุ—ก่อนที่มันจะถูกทำลาย— finalize()จะเรียกวิธี พิเศษของวัตถุนั้น วิธีการนี้สามารถเรียกใช้เพื่อปล่อยทรัพยากรเพิ่มเติมบางอย่างที่ใช้โดยวัตถุ วิธีการ นี้finalize()เป็นของคลาสวัตถุ กล่าวอีกนัยหนึ่ง มันคล้ายกับequals()และhashCode()( toString()ที่คุณเคยพบมาก่อน) ทุกวัตถุมีมัน มันต่างจากวิธีอื่นตรงที่...จะพูดยังไงดี...มันจงใจมาก โดยที่เราหมายความอย่างนั้นมันไม่ได้ถูกเรียกก่อนที่วัตถุจะถูกทำลายเสมอไป การเขียนโปรแกรมเป็นกิจกรรมที่แม่นยำมาก โปรแกรมเมอร์บอกให้คอมพิวเตอร์ทำบางอย่าง และคอมพิวเตอร์ก็ทำตามนั้น ฉันถือว่าคุณเคยชินกับพฤติกรรมแบบนี้แล้ว ดังนั้นในตอนแรกอาจเป็นเรื่องยากสำหรับคุณที่จะยอมรับแนวคิดต่อไปนี้: "ก่อนที่วัตถุจะถูกทำลาย เมธอดของคลาสอ็อบเจกต์จะถูกเรียกใช้หรือไม่ ถ้าเราโชคดีfinalize()! " ถึงกระนั้นนี่คือความจริง เครื่อง Java เองกำหนดว่าจะเรียก Finalize() เป็นกรณีไปหรือไม่ ในการทดสอบ ลองรันโค้ดต่อไปนี้:

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;// The first object becomes available for garbage collection here
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("The Cat is destroyed!");
   }
}
เราสร้างCatวัตถุ และในบรรทัดถัดไป เราไม่มีการอ้างอิงเพียงอย่างเดียวถึงวัตถุนั้น และเราทำอย่างนั้นเป็นล้านครั้ง เราได้ลบล้างfinalize()วิธีการ อย่างชัดเจน แต่ละครั้งที่Catวัตถุถูกทำลาย วัตถุนั้นจะต้องแสดงสตริงทั้งหมดหนึ่งล้านครั้ง แต่ไม่มี! พูดตามตรงคือในคอมพิวเตอร์ของฉันมีการดำเนินการเพียง37,346ครั้งเท่านั้น! กล่าวอีกนัยหนึ่ง เครื่อง Java ของฉันตัดสินใจที่จะเรียกใช้finalize()เมธอดเพียง 1 จากทุกๆ 27 กรณี ในกรณีอื่นๆ การรวบรวมขยะไม่เกี่ยวข้องกับการโทรนี้ ลองเรียกใช้รหัสนี้ด้วยตัวคุณเอง คุณมักจะได้ผลลัพธ์ที่แตกต่างออกไป อย่างที่คุณเห็น มันเป็นเรื่องยากที่จะโทรหาfinalize()พันธมิตรที่ไว้ใจได้ :) ดังนั้น นี่เป็นเคล็ดลับเล็กๆ น้อยๆ สำหรับอนาคต: อย่าพึ่งพาวิธีfinalize()การปล่อยทรัพยากรที่สำคัญJVM อาจเรียกมันหรือไม่ก็ได้ ใครจะรู้? หากอ็อบเจ็กต์ของคุณมีทรัพยากรที่มีความสำคัญต่อประสิทธิภาพ (เช่น การเชื่อมต่อฐานข้อมูลแบบเปิด) ในขณะที่มันยังมีชีวิตอยู่ จะเป็นการดีกว่าที่จะสร้างและเรียกเมธอดพิเศษอย่างชัดเจนเพื่อปล่อยเมื่ออ็อบเจ็กต์ไม่ต้องการอีกต่อไป ด้วยวิธีนี้ คุณจะทราบได้อย่างแน่นอนว่าประสิทธิภาพของโปรแกรมของคุณจะไม่ได้รับผลกระทบ เราเริ่มต้นด้วยการบอกว่าการทำงานกับหน่วยความจำและการรวบรวมขยะเป็นหัวข้อที่สำคัญมาก และมันก็เป็นเช่นนั้นจริงๆ การจัดการทรัพยากรอย่างไม่ถูกต้องและความเข้าใจผิดว่าล้างออบเจกต์ที่ไม่จำเป็นอย่างไรอาจนำไปสู่ข้อบกพร่องที่ไม่พึงประสงค์ที่สุดอย่างหนึ่ง: หน่วยความจำรั่ว นี่เป็นหนึ่งในข้อผิดพลาดในการเขียนโปรแกรมที่เป็นที่รู้จักมากที่สุด มันยังมีบทความ วิกิพีเดียของตัวเอง. โค้ดที่เขียนไม่ดีสามารถสร้างสถานการณ์ที่มีการจัดสรรหน่วยความจำทุกครั้งสำหรับออบเจกต์ที่สร้างขึ้นใหม่ แต่ออบเจ็กต์เก่าที่ไม่จำเป็นไม่พร้อมใช้งานสำหรับการรวบรวมขยะ เนื่องจากเราได้ทำการเปรียบเทียบหุ่นยนต์ดูดฝุ่นแล้ว ลองจินตนาการว่าจะเกิดอะไรขึ้นหากก่อนที่จะวิ่งหุ่นยนต์ คุณทำถุงเท้ากระจัดกระจายไปทั่วบ้าน ทุบแจกันแก้วแตก และทิ้งชิ้นส่วนเลโก้ไว้เต็มพื้น ตามธรรมชาติแล้ว หุ่นยนต์จะพยายามทำบางสิ่ง แต่วันหนึ่งมันก็จะยึดได้
วงจรชีวิตของวัตถุ - 3
เพื่อให้เครื่องดูดฝุ่นทำงานได้อย่างถูกต้อง คุณต้องรักษาพื้นให้อยู่ในสภาพที่เหมาะสมและหยิบจับทุกอย่างที่เครื่องดูดฝุ่นจับไม่ได้ คนเก็บขยะใช้หลักการเดียวกัน หากโปรแกรมมีวัตถุจำนวนมากที่ไม่สามารถทำความสะอาดได้ (เช่น ถุงเท้าหรือเลโก้สำหรับหุ่นยนต์ดูดฝุ่นของเรา) วันหนึ่งหน่วยความจำของเราจะหมด ไม่เพียงแต่โปรแกรมของคุณจะหยุดทำงานเท่านั้น โปรแกรมอื่นๆ ทั้งหมดที่ทำงานอยู่บนคอมพิวเตอร์ก็จะหยุดทำงานเช่นกัน ท้ายที่สุดพวกเขาจะไม่มีหน่วยความจำเพียงพอ (กลับไปที่การเปรียบเทียบของเรา กระจกแตกบนพื้นไม่เพียงหยุดเครื่องดูดฝุ่นเท่านั้น แต่ยังรวมถึงผู้คนที่อาศัยอยู่ในบ้านด้วย) กล่าวโดยย่อ นี่คือลักษณะของวัฏจักรชีวิตของวัตถุและการรวบรวมขยะใน Java คุณไม่จำเป็นต้องจำสิ่งนี้ เพียงแค่เข้าใจวิธีการทำงานก็เพียงพอแล้ว ในบทเรียนต่อไป เรา จะกลับไปที่กระบวนการเหล่านี้โดยละเอียด แต่ตอนนี้คุณสามารถกลับไปแก้ไขงาน CodeGym ได้ :) โชคดี!
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION