คำนำ
ฉันเห็นคำถามเกี่ยวกับ SegmentFault: Java มีกลไก GC ที่สมบูรณ์ดังนั้นจะมีปัญหาการรั่วไหลของหน่วยความจำใน Java และฉันสามารถให้กรณีการรั่วไหลของหน่วยความจำได้หรือไม่ มุมมองคำถามนี้ให้คำตอบที่สมบูรณ์สำหรับคำถามนี้
ความรู้เบื้องต้นเกี่ยวกับกลไกการรีไซเคิลขยะ
ในระหว่างการทำงานของโปรแกรมแต่ละวัตถุจะถูกสร้างขึ้นจะมีการจัดสรรหน่วยความจำจำนวนหนึ่งเพื่อจัดเก็บข้อมูลวัตถุ หากคุณเพิ่งจัดสรรหน่วยความจำโปรแกรมจะเผชิญกับปัญหาของหน่วยความจำไม่เพียงพอไม่ช้าก็เร็ว ดังนั้นในภาษาใด ๆ จะมีกลไกการกู้คืนหน่วยความจำเพื่อเพิ่มหน่วยความจำของวัตถุที่หมดอายุเพื่อให้แน่ใจว่าสามารถนำหน่วยความจำกลับมาใช้ใหม่ได้
กลไกการรีไซเคิลหน่วยความจำสามารถแบ่งออกเป็นสองประเภทตามบทบาทการใช้งาน หนึ่งคือโปรแกรมเมอร์ตระหนักถึงการเปิดตัวหน่วยความจำด้วยตนเอง (เช่นภาษา C) และอีกอย่างคือกลไกการรีไซเคิลหน่วยความจำในตัวของภาษาเช่นกลไกการรวบรวม Java Garbage ที่จะแนะนำในบทความนี้
กลไกการรวบรวมขยะของ Java
ในสภาพแวดล้อมรันไทม์ของโปรแกรม Java Virtual Machine ให้บริการคอลเลกชันขยะระดับระบบ (GC, คอลเลกชันคาร์โบไฮเดรต) ซึ่งรับผิดชอบในการเรียกคืนหน่วยความจำที่ถูกครอบครองโดยวัตถุที่สูญเสียการอ้างอิง ข้อกำหนดเบื้องต้นสำหรับการทำความเข้าใจ GC คือการเข้าใจแนวคิดบางอย่างที่เกี่ยวข้องกับการรวบรวมขยะ แนวคิดเหล่านี้ได้รับการแนะนำทีละหนึ่งในต่อไปนี้
สถานะของวัตถุในพื้นที่กอง JVM
อินสแตนซ์ของวัตถุ Java จะถูกเก็บไว้ในพื้นที่กองของ JVM สำหรับเธรด GC วัตถุเหล่านี้มีสามสถานะ
1. สถานะที่สัมผัสได้: มีการอ้างอิงตัวแปรในโปรแกรมดังนั้นวัตถุนี้จึงเป็นสถานะที่สัมผัสได้
2. สถานะที่เปิดใช้งานใหม่: เมื่อไม่มีตัวแปรในโปรแกรมอ้างถึงวัตถุนี้วัตถุจะเปลี่ยนจากสถานะที่สัมผัสได้เป็นสถานะที่เปิดใช้งานอีกครั้ง เธรด CG จะเตรียมที่จะเรียกวิธีการสรุปของวัตถุนี้ในเวลาที่กำหนด (วิธีการสรุปจะสืบทอดหรือเขียนวัตถุลูกใหม่) รหัสในวิธีสุดท้ายอาจแปลงวัตถุให้เป็นสถานะที่สัมผัสได้มิฉะนั้นวัตถุจะถูกแปลงเป็นสถานะที่ไม่สามารถแตะต้องได้
3. สถานะที่ไม่สามารถแตะต้องได้: เธรด GC สามารถรีไซเคิลหน่วยความจำของวัตถุนี้เฉพาะเมื่อวัตถุอยู่ในสถานะที่ไม่สามารถแตะต้องได้
ในการปล่อยวัตถุอย่างถูกต้อง GC จะต้องตรวจสอบสถานะการทำงานของแต่ละวัตถุรวมถึงแอปพลิเคชันการอ้างอิงการอ้างอิงการมอบหมาย ฯลฯ GC จำเป็นต้องตรวจสอบดังนั้น GC จะรู้ว่าไม่ว่าวัตถุจะอยู่ในสถานะใดข้างต้นหรือไม่
ดังที่ได้กล่าวไว้ข้างต้นเธรด GC จะดำเนินการวิธีการสุดท้ายของวัตถุสถานะที่ฟื้นคืนชีพได้ในเวลาที่กำหนด แล้วจะดำเนินการเมื่อไหร่? เนื่องจากผู้ดำเนินการ JVM ที่แตกต่างกันอาจใช้อัลกอริทึมที่แตกต่างกันเพื่อจัดการ GC ได้ตลอดเวลานักพัฒนาไม่สามารถทำนายระยะเวลาของเธรด GC ที่ดำเนินการต่าง ๆ (รวมถึงการตรวจจับสถานะวัตถุการปล่อยหน่วยความจำวัตถุและวิธีการเรียกวัตถุที่เรียกจบ) แม้ว่าเธรด GC สามารถเตือนให้ดำเนินการรวบรวมขยะโดยเร็วที่สุดเท่าที่จะเป็นไปได้ผ่านฟังก์ชั่น System.gc () และ runtime.gc () สิ่งนี้ไม่สามารถรับประกันได้ว่าเธรด GC จะดำเนินการรีไซเคิลที่สอดคล้องกันทันที
หน่วยความจำรั่วไหล
การรั่วไหลของหน่วยความจำเกิดจากการออกแบบที่ไม่ถูกต้องซึ่งโปรแกรมไม่สามารถปล่อยหน่วยความจำที่ไม่ได้ใช้อีกต่อไปส่งผลให้เสียทรัพยากร GC จะทำความสะอาดหน่วยความจำที่ครอบครองโดยวัตถุที่สูญเสียการอ้างอิงโดยอัตโนมัติ อย่างไรก็ตามหากมีการอ้างอิงวัตถุบางอย่างเนื่องจากข้อผิดพลาดในการเขียนโปรแกรมการรั่วไหลของหน่วยความจำจะเกิดขึ้น
ตัวอย่างเช่นตัวอย่างต่อไปนี้ อาร์เรย์ถูกใช้เพื่อใช้สแต็กโดยมีการดำเนินการสองครั้ง: การเข้าสแต็กและทางออกสแต็ก
นำเข้า com.sun.javafx.collections.elementobservableListDecorator; นำเข้า com.sun.swing.internal.plaf.metal.resources.metal_sv; นำเข้า Java.beans.exceptionListener; */Mystack คลาสสาธารณะ {วัตถุส่วนตัว [] องค์ประกอบ; การเพิ่มจำนวน int ส่วนตัว = 10; ขนาด int ส่วนตัว = 0; mystack สาธารณะ (ขนาด int) {องค์ประกอบ = วัตถุใหม่ [ขนาด]; } // วางโมฆะสาธารณะสแต็ก (วัตถุ o) {ความสามารถ (); องค์ประกอบ [ขนาด ++] = o; } // วางวัตถุสาธารณะสแต็กป๊อป () {ถ้า (ขนาด == 0) โยน emptystackexception ใหม่ (); องค์ประกอบกลับ [-ขนาด]; } // เพิ่มความสามารถของความจุโมฆะส่วนตัวสแต็ก () {ถ้า (องค์ประกอบความยาว! = ขนาด) กลับมา; Object [] newArray = วัตถุใหม่ [elements.length + เพิ่มขึ้น]; System.arrayCopy (องค์ประกอบ, 0, Newarray, 0, ขนาด); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {mystack stack = mystack ใหม่ (100); สำหรับ (int i = 0; i <100; i ++) stack.push (จำนวนเต็มใหม่ (i)); สำหรับ (int i = 0; i <100; i ++) {system.out.println (stack.pop (). toString ()); -โปรแกรมนี้พร้อมใช้งานและรองรับการเข้าร่วมสแต็กทั่วไปและการดำเนินการเข้าสแต็ก อย่างไรก็ตามมีปัญหาที่ไม่ได้รับการจัดการที่ดีนั่นคือเมื่อการดำเนินการสแต็กถูกปล่อยออกมาการอ้างอิงถึงองค์ประกอบสแต็กในอาร์เรย์จะไม่ถูกปล่อยออกมาซึ่งทำให้โปรแกรมอ้างอิงถึงวัตถุนี้ (วัตถุนี้อ้างอิงโดยอาร์เรย์) GC เชื่อเสมอว่าวัตถุนี้สามารถเข้าถึงได้ซึ่งหมายความว่าไม่จำเป็นต้องพูดคุยเกี่ยวกับการปล่อยหน่วยความจำ นี่เป็นกรณีทั่วไปของการรั่วไหลของหน่วยความจำ สำหรับสิ่งนี้รหัสที่แก้ไขคือ:
// สแต็กวัตถุสาธารณะป๊อป () {ถ้า (ขนาด == 0) โยน emptystackexception ใหม่ (); วัตถุ o = องค์ประกอบ [-ขนาด]; องค์ประกอบ [ขนาด] = null; กลับมา; -บทความข้างต้นมีความเข้าใจอย่างลึกซึ้งเกี่ยวกับกลไกการรวบรวมขยะ Java และการรั่วไหลของหน่วยความจำ นี่คือเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่ามันจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น