Java Thread ขยะเก็บได้หรือไม่


85

คำถามนี้ถูกโพสต์ในบางไซต์ ฉันไม่พบคำตอบที่ถูกต้องดังนั้นฉันจึงโพสต์ที่นี่อีกครั้ง

public class TestThread {
    public static void main(String[] s) {
        // anonymous class extends Thread
        Thread t = new Thread() {
            public void run() {
                // infinite loop
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    // as long as this line printed out, you know it is alive.
                    System.out.println("thread is running...");
                }
            }
        };
        t.start(); // Line A
        t = null; // Line B
        // no more references for Thread t
        // another infinite loop
        while (true) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            System.gc();
            System.out.println("Executed System.gc()");
        } // The program will run forever until you use ^C to stop it
    }
}

คำถามของฉันไม่เกี่ยวกับการหยุดเธรด ให้ฉันเรียบเรียงคำถามใหม่ บรรทัด A (ดูโค้ดด้านบน) เริ่มเธรดใหม่ และบรรทัด B ทำให้การอ้างอิงเธรดเป็นโมฆะ ดังนั้นตอนนี้ JVM จึงมี Thread Object (ซึ่งอยู่ในสถานะกำลังรัน) ซึ่งไม่มีการอ้างอิง (เป็น t = null ในบรรทัด B) ดังนั้นคำถามของฉันคือทำไมเธรดนี้ (ซึ่งไม่มีการอ้างอิงอีกต่อไปในเธรดหลัก) ยังคงทำงานต่อไปจนกว่าเธรดหลักจะทำงาน ตามความเข้าใจของฉันวัตถุเธรดควรเป็นขยะที่รวบรวมโพสต์บรรทัด B ฉันพยายามเรียกใช้รหัสนี้เป็นเวลา 5 นาทีขึ้นไปขอให้ Java Runtime รัน GC แต่เธรดก็ไม่หยุด

หวังว่าทั้งรหัสและคำถามจะชัดเจนในครั้งนี้

คำตอบ:


124

เธรดที่กำลังรันถือเป็นสิ่งที่เรียกว่ารูทการรวบรวมขยะและเป็นหนึ่งในสิ่งเหล่านั้นที่ป้องกันไม่ให้ขยะถูกรวบรวม เมื่อตัวรวบรวมขยะระบุว่าวัตถุของคุณ ' เข้าถึงได้ ' หรือไม่ก็มักจะทำเช่นนั้นโดยใช้ชุดของรากตัวเก็บขยะเป็นจุดอ้างอิง

ลองพิจารณาสิ่งนี้ทำไมเธรดหลักของคุณจึงไม่ถูกรวบรวมขยะไม่มีใครอ้างถึงเรื่องนั้น


17
คำตอบนี้ในปัจจุบันทำให้เกิดคำถามว่าเธรดสามารถ GC ได้หรือไม่ (หลังจากสิ้นสุด) เนื่องจากคำถามนี้ถูกทำเครื่องหมายว่าซ้ำกับคำถามนี้จึงควรระบุว่าเธรดจะไม่ถูกทำเครื่องหมายเป็น "รากการรวบรวมขยะ" อีกต่อไปหลังจากสิ้นสุดการทำงานและด้วยเหตุนี้ GC จึงสามารถเข้าถึงได้
bluenote10

13
ประโยคสุดท้ายเจาะลึก: "ทำไมกระทู้หลักของคุณถึงไม่เป็นขยะ ... "
กำหนด

ดังนั้นในการติดตามผลเธรดที่จำหน่ายไปแล้ว (อันที่เข้าร่วม) จะไม่ถือว่าเป็นรูทอีกต่อไปหรือไม่? ฉันเกือบจะแน่ใจว่าคำตอบคือใช่ แต่ฉันเห็นสิ่งแปลก ๆ ในแอปพลิเคชันของฉันภายใต้ตัวสร้างโปรไฟล์และทำให้ฉันสงสัย ...
Groostav

1
ยิ่งฉันอ่านคำตอบมากเท่าไหร่ฉันก็ยิ่งสับสนมากขึ้น แต่ใช่แล้วทำไมเธรดหลักจึงไม่ได้รับการรวบรวมขยะจึงเป็นสิ่งที่ต้องไตร่ตรอง แต่กลับมาที่คำถามหลักหากเธรดย่อยสร้างอ็อบเจ็กต์บางอย่างมันจะไม่ได้รับ GCed เนื่องจากเธรดหลักยังคงทำงานอยู่และเก็บการอ้างอิงของเธรดย่อยแม้ว่าพวกเขาจะ 'วิ่ง' หมดแล้วก็ตาม (!! ??)
Rahul Kumar

@Groostav เธรดที่เข้าร่วมแล้วไม่ทำงานดังนั้นจึงไม่ใช่รูทการรวบรวมขยะ แต่เมื่อด้ายปกครองที่เรียกว่ามันมีการอ้างอิงถึงchild.join() childหากการอ้างอิงนั้น (และอื่น ๆ ) ไม่ถูกละทิ้งเธรดย่อยจะไม่สามารถ GCed ได้
Blaisorblade

23

ตามที่อธิบายไว้การรันเธรดเป็นไปตามคำนิยามภูมิคุ้มกันต่อ GC GC เริ่มทำงานโดยการสแกน "ราก" ซึ่งถือว่าสามารถเข้าถึงได้ตลอดเวลา รากประกอบด้วยตัวแปรโกลบอล ("ฟิลด์สแตติก" ใน Java-talk) และสแต็กของเธรดที่รันอยู่ทั้งหมด (สามารถจินตนาการได้ว่าสแต็กของเธรดที่รันอยู่อ้างอิงThreadอินสแตนซ์ที่เกี่ยวข้อง)

อย่างไรก็ตามคุณสามารถทำให้เธรดเป็นเธรด "daemon" ได้ (ดูThread.setDaemon(boolean)) เธรด daemon ไม่ได้รวบรวมขยะมากกว่าเธรดที่ไม่ใช่ daemon แต่ JVM จะออกเมื่อเธรดที่รันอยู่ทั้งหมดเป็น daemon วิธีหนึ่งที่จะจินตนาการได้ก็คือทุกเธรดเมื่อสิ้นสุดการทำงานจะตรวจสอบว่ายังมีเธรดที่รันที่ไม่ใช่ดีมอนอยู่หรือไม่ ถ้าไม่เธรดการยุติจะบังคับให้มีการSystem.exit()เรียกซึ่งออกจาก JVM (การฆ่าเธรด daemon ที่กำลังรันอยู่) นี่ไม่ใช่ปัญหาเกี่ยวกับ GC ในลักษณะที่มีการจัดสรรเธรดด้วยตนเอง อย่างไรก็ตามนี่คือวิธีที่ JVM สามารถทนต่อเธรดกึ่งโกงได้ โดยทั่วไปจะใช้สำหรับTimerอินสแตนซ์


19

JVM มีการอ้างอิงถึงเธรดที่รันอยู่ทั้งหมด

จะไม่มีการรวบรวมเธรด (หรือสิ่งที่อ้างถึง) ในขณะที่ยังทำงานอยู่


13

เธรดไม่ใช่ขยะที่รวบรวมเนื่องจากมีการอ้างอิงไปยังเธรดที่คุณมองไม่เห็น ตัวอย่างเช่นมีการอ้างอิงในระบบรันไทม์

เมื่อเธรดถูกสร้างขึ้นเธรดจะถูกเพิ่มลงในกลุ่มเธรดปัจจุบัน คุณสามารถรับรายการเธรดในกลุ่มเธรดปัจจุบันได้ดังนั้นจึงเป็นอีกวิธีหนึ่งในการอ้างอิงถึงเธรด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.