ความแตกต่างระหว่าง SoftReference และ WeakReference ใน Java คืออะไร


810

ความแตกต่างระหว่างjava.lang.ref.WeakReferenceและjava.lang.ref.SoftReferenceคืออะไร


9
SoftReferences เป็นประเภทของ (ไม่ใช่จริงๆ แต่เพื่อประโยชน์ในการอภิปราย) WeakReferences ซึ่งมักจะถูกรวบรวมเมื่อ JVM คิดว่าหน่วยความจำไม่เพียงพอ
Ajeet Ganga

5
@AjeetGanga การอ้างอิงที่ไม่รัดกุมจะถูกรวบรวมเสมอเมื่อใดก็ตามที่ GC ทำงาน ดูstackoverflow.com/a/46291143/632951
Pacerier

คำตอบ:


927

จากการทำความเข้าใจข้อมูลอ้างอิงที่อ่อนแอโดย Ethan Nicholas:

ข้อมูลอ้างอิงที่อ่อนแอ

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

WeakReference weakWidget = new WeakReference(widget);

และที่อื่นในรหัสคุณสามารถใช้ weakWidget.get()รับWidgetวัตถุจริง แน่นอนการอ้างอิงที่อ่อนแอยังไม่แข็งแรงพอที่จะป้องกันการรวบรวมขยะดังนั้นคุณอาจพบ (หากไม่มีการอ้างอิงที่รัดกุมในวิดเจ็ต) ที่ weakWidget.get()เริ่มส่งคืนnullทันที

...

อ้างอิงอ่อน

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

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

และ Peter Kessler เพิ่มในความคิดเห็น:

Sun JRE ปฏิบัติ SoftReferences ต่างจาก WeakReferences เราพยายามที่จะยึดวัตถุที่อ้างอิงโดย SoftReference หากไม่มีแรงกดดันต่อหน่วยความจำที่มีอยู่ รายละเอียดหนึ่ง: นโยบายสำหรับ "-client" และ "-server" JRE นั้นแตกต่างกัน: -client JRE พยายามรักษารอยเท้าของคุณให้เล็กลงโดยเลือกที่จะล้าง SoftReferences แทนการขยายฮีปในขณะที่ -verver JRE พยายามที่จะทำให้คุณ ประสิทธิภาพสูงโดยเลือกที่จะขยายฮีป (ถ้าเป็นไปได้) แทนที่จะล้าง SoftReferences ขนาดเดียวไม่พอดีทั้งหมด


7
ไม่มีโพสต์อีกต่อไปคุณสามารถค้นหาได้บนเครื่อง wayback: web.archive.org/web/20061130103858/http://weblogs.java.net/blog/…
riccardo.tasso

เวลานี้การเก็บถาวรไม่พร้อมใช้งานอีกต่อไป
user1506104

209

การอ้างอิงที่อ่อนแอจะถูกรวบรวมอย่างกระตือรือร้น หาก GC พบว่าวัตถุนั้นสามารถเข้าถึงได้อย่างอ่อน (เข้าถึงได้จากการอ้างอิงที่อ่อนแอเท่านั้น) มันจะล้างการอ้างอิงที่อ่อนแอไปยังวัตถุนั้นทันที เช่นนี้จะเป็นการดีสำหรับการอ้างอิงถึงวัตถุที่โปรแกรมของคุณเก็บไว้ (อ้างอิงอย่างยิ่ง) "ข้อมูลที่เกี่ยวข้อง" ซึ่งเป็นที่อื่นเช่นการสะท้อนแคชที่เกี่ยวกับคลาสหรือ wrapper สำหรับวัตถุ ฯลฯ สิ่งใดก็ตามที่ทำให้ ไม่มีเหตุผลที่จะเก็บไว้หลังจากวัตถุที่เกี่ยวข้องกับนั้นคือ GC-ed เมื่อการอ้างอิงที่อ่อนแอได้รับการเคลียร์จะได้รับการจัดคิวในคิวการอ้างอิงที่รหัสของคุณสำรวจที่ไหนสักแห่งและมันจะทิ้งวัตถุที่เกี่ยวข้องเช่นกัน นั่นคือคุณเก็บข้อมูลเพิ่มเติมเกี่ยวกับวัตถุ แต่ไม่จำเป็นต้องใช้ข้อมูลนั้นเมื่อวัตถุที่อ้างถึงหายไป อันที่จริงแล้ว ในบางสถานการณ์คุณยังสามารถคลาสย่อย WeakReference และเก็บข้อมูลพิเศษที่เกี่ยวข้องเกี่ยวกับวัตถุในฟิลด์ของคลาสย่อย WeakReference การใช้งานทั่วไปของ WeakReference ร่วมกับแผนที่เพื่อรักษาอินสแตนซ์แบบบัญญัติ

ในทางกลับกัน SoftReferences นั้นดีสำหรับการแคชภายนอกทรัพยากรที่สามารถกู้คืนได้เนื่องจาก GC โดยทั่วไปจะเลื่อนการล้างออกไป มีการรับประกันว่า SoftReferences ทั้งหมดจะถูกล้างก่อนที่ OutOfMemoryError จะถูกโยนดังนั้นพวกเขาจึงไม่สามารถทำให้ OOME [*] ตามหลักวิชาได้

ตัวอย่างกรณีการใช้งานทั่วไปคือการเก็บรูปแบบการแยกวิเคราะห์เนื้อหาจากไฟล์ คุณจะใช้ระบบที่คุณจะโหลดไฟล์แยกวิเคราะห์และเก็บ SoftReference ให้กับวัตถุรูทของการแทนคำ ครั้งต่อไปที่คุณต้องการไฟล์คุณจะพยายามดึงไฟล์ผ่าน SoftReference หากคุณสามารถเรียกคืนได้คุณจะได้รับภาระ / การแยกวิเคราะห์อีกครั้งและหาก GC ลบออกในระหว่างนั้นคุณจะโหลดซ้ำ ด้วยวิธีนี้คุณใช้หน่วยความจำฟรีเพื่อเพิ่มประสิทธิภาพ แต่ไม่เสี่ยงต่อ OOME

ตอนนี้สำหรับ [*] การรักษา SoftReference ไม่สามารถทำให้ OOME อยู่ในตัวได้ หากในทางตรงกันข้ามคุณใช้ SoftReference โดยไม่ตั้งใจสำหรับงาน WeakReference นั้นควรใช้ (กล่าวคือคุณเก็บข้อมูลที่เกี่ยวข้องกับวัตถุที่อ้างอิงอย่างใดอย่างหนึ่งและทิ้งไว้เมื่อวัตถุอ้างอิงได้รับการเคลียร์) คุณสามารถเรียกใช้เป็น OOME เป็น รหัสของคุณที่โพล ReferenceQueue และทิ้งวัตถุที่เกี่ยวข้องอาจเกิดขึ้นไม่ทำงานในเวลาที่เหมาะสม

ดังนั้นการตัดสินใจขึ้นอยู่กับการใช้งาน - หากคุณแคชข้อมูลที่มีราคาแพงในการสร้าง แต่ยังสร้างขึ้นใหม่จากข้อมูลอื่น ๆ ให้ใช้การอ้างอิงแบบนุ่มนวล - หากคุณทำการอ้างอิงกับอินสแตนซ์มาตรฐานของข้อมูลบางส่วนหรือคุณต้องการ มีการอ้างอิงไปยังวัตถุโดยไม่มี "เป็นเจ้าของ" มัน (ดังนั้นการป้องกันไม่ให้มันเป็น GC'd) ให้ใช้การอ้างอิงที่อ่อนแอ


14
มีประโยชน์อย่างยิ่งสำหรับคำอธิบายว่าจะใช้วัตถุที่อ่อนแอเมื่อใด
แจ็ค BeNimble

ประเด็นสำคัญเกี่ยวกับการใช้งานที่เหมาะสมของ a WeakReferenceคือในสถานที่ที่ควรใช้งานความจริงที่ว่าหนึ่งอาจยังคงใช้งานได้เพียงเล็กน้อยในขณะที่หลังจากการอ้างอิงไปนอกขอบเขตอาจจะทนได้ แต่ไม่พึงประสงค์
supercat

ฉันพยายามที่จะเข้าใจว่าการใช้ WeakHashMap คืออะไรถ้ามันสร้างการอ้างอิงที่อ่อนแอไปยังวัตถุค่าที่สำคัญ

@supercat มีเพียงการใช้งานที่เหมาะสมเพียงข้อเดียวเท่านั้นWeakReferenceคือสังเกตการทำงานของ GC ดูรายละเอียดเพิ่มเติมได้ที่: stackoverflow.com/a/46291143/632951
Pacerier

1
@Pacerier: ผู้เขียนโพสต์นั้นผิด เขาละเลยสถานการณ์การใช้งานอื่น ๆ เช่นการสมัครสมาชิกเหตุการณ์จุดที่สองของเขาไร้สาระและจุดที่สามของเขาสันนิษฐานว่าโปรแกรมเมอร์สามารถทำสิ่งต่าง ๆ ที่อาจเป็นไปไม่ได้ ประเด็นแรกของเขามีเหตุผล แต่ก็ผูกกับสิ่งที่ฉันพูดโดยตรง หากรหัสจะต้องสร้างและเปรียบเทียบวัตถุที่ไม่เปลี่ยนรูปขนาดใหญ่บ่อยครั้งเช่นส่วนอาคารจะถูกกว่าหากรหัสสร้างวัตถุใหม่โดยไม่คำนึงว่ามีอยู่จริงหรือไม่ แต่การเปรียบเทียบระหว่างวัตถุกับตัวเอง (การอ้างอิงที่เหมือนกัน) จะเป็น ...
supercat

155

ใน Java ; สั่งซื้อจากที่แข็งแกร่งถึงที่อ่อนแอที่สุดมี: ที่แข็งแกร่งนุ่มที่อ่อนแอและผี

การอ้างอิงที่แข็งแกร่งคือการอ้างอิงปกติที่ปกป้องวัตถุที่อ้างอิงจากการรวบรวมโดย GC นั่นคือไม่เคยเก็บขยะ

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

การอ้างอิงที่อ่อนแอเป็นการอ้างอิงที่ไม่ได้ป้องกันวัตถุที่อ้างอิงจากการรวบรวมโดย GC เช่นขยะเก็บรวบรวมเมื่อไม่มีการอ้างอิงที่แข็งแกร่งหรืออ่อน

การอ้างอิง Phantomเป็นการอ้างอิงไปยังวัตถุที่มีการอ้างอิง phantomly หลังจากที่ได้รับการสรุป แต่ก่อนที่หน่วยความจำที่จัดสรรไว้ได้รับการเรียกคืน

แหล่ง

การเปรียบเทียบ:สมมติว่า JVM เป็นอาณาจักรวัตถุเป็นกษัตริย์ของอาณาจักรและ GC เป็นผู้โจมตีของราชอาณาจักรที่พยายามฆ่ากษัตริย์ (วัตถุ)

  • เมื่อคิงแข็งแกร่ง , GC ไม่สามารถฆ่าเขาได้
  • เมื่อ King อ่อน , GC โจมตีเขา แต่ King ปกครองอาณาจักรด้วยการป้องกันจนกว่าทรัพยากรจะพร้อมใช้งาน
  • เมื่อ King อ่อนแอเขาจะจู่โจม GC แต่เขาจะปกครองอาณาจักรโดยไม่มีการป้องกัน
  • เมื่อราชาคือPhantom , GC ฆ่าเขาไปแล้ว แต่ราชาก็มีให้ผ่านทางวิญญาณของเขา

7
อ้างอิงอ่อน ... until memory is availableไม่สมเหตุสมผล คุณหมายถึงis eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another useอะไร
ToolmakerSteve

1
ใช่ตัวรวบรวมขยะจะไม่รวบรวมข้อมูลอ้างอิงจนกว่าหน่วยความจำจะพร้อมใช้งาน
Premraj

2
ฉันชอบสิ่งที่อธิบายง่าย ๆ โดยไม่มี bla bla bla +1 มากเกินไปจากฉัน!
Adelin

3
สรุปที่ยอดเยี่ยมพร้อมตัวอย่างที่เป็นนวัตกรรม
Ravindra babu

+1 อ่านเพิ่มเติม: javarevisited.blogspot.in/2014/03/…
roottraveller

77

การอ้างอิงที่อ่อนแอ http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

หลักการ: weak referenceเกี่ยวข้องกับการเก็บขยะ โดยปกติวัตถุที่มีอย่างน้อยหนึ่งรายการreferenceจะไม่มีสิทธิ์ได้รับการรวบรวมขยะ หลักการข้างต้นไม่บังคับเมื่อมันเป็น
weak referenceหากวัตถุมีการอ้างอิงที่อ่อนแอกับวัตถุอื่นเท่านั้นแสดงว่าพร้อมสำหรับการรวบรวมขยะ

ลองดูตัวอย่างด้านล่าง: เรามีMapกับวัตถุที่สำคัญคือการอ้างอิงวัตถุ

import java.util.HashMap;   
public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> aMap = new 
                       HashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        System.out.println("Size of Map" + aMap.size());

    }
}

emp = nullตอนนี้ในระหว่างการทำงานของโปรแกรมที่เราได้ทำ การMapถือกุญแจนั้นไม่สมเหตุสมผลnullเลย ในสถานการณ์ข้างต้นวัตถุไม่ได้เก็บรวบรวมขยะ

WeakHashMap

WeakHashMapเป็นหนึ่งในสถานที่ที่รายการ ( key-to-value mappings) Mapจะถูกลบออกเมื่อมันเป็นไปไม่ได้ที่จะดึงพวกเขาออกจาก

ให้ฉันแสดงตัวอย่างข้างต้นเช่นเดียวกันกับWeakHashMap

import java.util.WeakHashMap;

public class Test {

    public static void main(String args[]) {
        WeakHashMap<Employee, EmployeeVal> aMap = 
                    new WeakHashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        int count = 0;
        while (0 != aMap.size()) {
            ++count;
            System.gc();
        }
        System.out.println("Took " + count
                + " calls to System.gc() to result in weakHashMap size of : "
                + aMap.size());
    }
}

ผลลัพธ์:ใช้20 calls to System.gc()ผลลัพธ์เป็นaMap size: 0

WeakHashMapมีเพียงการอ้างอิงที่อ่อนแอไปยังคีย์ไม่ใช่การอ้างอิงที่แข็งแกร่งเช่นMapคลาสอื่น ๆ WeakHashMapมีสถานการณ์ที่คุณต้องดูแลเมื่อค่าหรือคีย์มีการอ้างอิงอย่างยิ่งว่าคุณได้ใช้เป็น นี้สามารถหลีกเลี่ยงได้โดยการตัดวัตถุในWeakReference

import java.lang.ref.WeakReference;
import java.util.HashMap;

public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> map = 
                      new HashMap<Employee, EmployeeVal>();
        WeakReference<HashMap<Employee, EmployeeVal>> aMap = 
                       new WeakReference<HashMap<Employee, EmployeeVal>>(
                map);

        map = null;

        while (null != aMap.get()) {
            aMap.get().put(new Employee("Vinoth"),
                    new EmployeeVal("Programmer"));
            System.out.println("Size of aMap " + aMap.get().size());
            System.gc();
        }
        System.out.println("Its garbage collected");
    }
}

อ้างอิงอ่อน

Soft Referenceมีความแข็งแกร่งเล็กน้อยที่อ้างอิงอ่อนแอ การอ้างอิงแบบนุ่มช่วยให้สามารถรวบรวมขยะได้ แต่ขอให้ผู้รวบรวมขยะทำการล้างเฉพาะในกรณีที่ไม่มีตัวเลือกอื่น

ตัวรวบรวมขยะไม่ได้รวบรวมวัตถุที่เข้าถึงได้อย่างเบา ๆ อย่างที่มันทำกับวัตถุที่เข้าถึงได้ง่าย แต่จะรวบรวมเฉพาะวัตถุที่เข้าถึงได้อย่างนุ่มนวลหากหน่วยความจำต้องการ การอ้างอิงอย่างนุ่มนวลเป็นวิธีการพูดกับตัวเก็บขยะ "ตราบใดที่หน่วยความจำไม่แน่นเกินไปฉันก็อยากจะเก็บวัตถุนี้ไว้รอบ ๆ แต่ถ้าหน่วยความจำแน่นจริงๆให้ไปข้างหน้าและรวบรวมมันแล้วฉันจะจัดการ กับสิ่งนั้น " ตัวรวบรวมขยะจำเป็นต้องเคลียร์การอ้างอิงแบบอ่อนทั้งหมดก่อนที่จะสามารถโยนOutOfMemoryErrorได้


5
คุณอาจได้รับในNullPointerException aMap.get().put(...)
xehpuk

ตัวอย่าง HashMap แรกของคุณดูผิด เมื่อคุณทำ "aMap.put (emp, val);" ทั้ง 'emp' และ 'val' เป็นแหล่งอ้างอิงที่แข็งแกร่ง ภายในตัวแปรใหม่จะถูกสร้างขึ้นเพื่อเก็บ 'emp' และ 'val' ดังนั้นเมื่อคุณทำ "emp = null;" คุณแค่ลบล้างตัวแปร "emp" แต่ไม่ใช่ตัวแปรภายในแผนที่ hash (ซึ่งยังคงเก็บออบเจกต์ Employee เดิมไว้) ดังนั้นแผนที่แฮชจะยังคงมีการอ้างอิงที่แข็งแกร่งถึง 'emp' โดยไม่คำนึงถึงสิ่งที่คุณทำกับตัวแปร 'emp' ภายนอก
Tiago

@Tiago ไม่น่าจะเป็นเพราะ "ตัวอย่างแรก" คุณกำลังอ้างถึงWeakHashMapตัวอย่าง (เนื่องจากเป็นตัวอย่างแรกที่แสดงให้เห็นถึงพฤติกรรมที่อ่อนแอ) ดูเอกสารสำหรับ "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. " จุดทั้งหมดของการใช้ WeakHashMap คือคุณไม่ต้องประกาศ / ส่งผ่าน WeakReference WeakHashMap ทำเพื่อคุณภายใน docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
ToolmakerSteve

เอา 0 การเรียกไปที่ System.gc () เพื่อส่งผลให้ขนาด weakHashMap ของ: 0 เป็นผลลัพธ์ของโปรแกรมที่สองของคุณ?
Adelin

1
อีกตัวอย่างหนึ่งของWeakHashMapการทำงานพร้อมแอพตัวอย่างที่แสดงให้เห็นว่ารายการจะถูกลบออกได้อย่างไรหลังจากเรียกใช้งานคอลเลกชันขยะดูคำตอบสำหรับคำถามของฉันWeakHashMap เติบโตขึ้นเรื่อย ๆ หรือไม่หรือลบคีย์ขยะออก .
Basil Bourque

50

ความแตกต่างที่แท้จริงเพียงอย่างเดียวระหว่างการอ้างอิงแบบนุ่มนวลและการอ้างอิงแบบอ่อนคือ

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


@ ATorras, Samir ฉันขยายคำตอบนี้ที่นี่: stackoverflow.com/a/46291143/632951
Pacerier

25

SoftReferenceถูกออกแบบมาสำหรับแคช เมื่อพบว่ามีWeakReferenceการอ้างอิงวัตถุที่ไม่สามารถเข้าถึงได้มิฉะนั้นจะถูกลบทันที SoftReferenceอาจถูกทิ้งไว้ตามที่เป็นอยู่ โดยทั่วไปจะมีอัลกอริทึมที่เกี่ยวข้องกับจำนวนหน่วยความจำที่ว่างและเวลาที่ใช้ล่าสุดเพื่อตรวจสอบว่าควรจะล้าง อัลกอริทึม Sun ปัจจุบันคือการล้างข้อมูลอ้างอิงหากไม่ได้ใช้งานในไม่กี่วินาทีเนื่องจากมีหน่วยความจำเมกะไบต์ฟรีบน Java heap (กำหนดค่าได้ HotSpot เซิร์ฟเวอร์จะตรวจสอบกับ heap ที่เป็นไปได้สูงสุดตามที่กำหนดโดย-Xmx) SoftReferences จะถูกล้างก่อนที่OutOfMemoryErrorจะถูกโยนเว้นแต่จะเข้าถึงได้เป็นอย่างอื่น


9
แต่ใน Android ไม่แนะนำให้ใช้กับแคชสำหรับdeveloper.android.com/reference/java/lang/ref/…
Yaroslav Mytkalyk

4
@DoctororDrive tbf คำถามเกี่ยวกับ java ไม่ใช่ Dalvik! :-P
fabspro

2
@YaroslavMytkalyk, ตรงไปตรงมาถ้า Android ต้องการที่จะเขียนพฤติกรรมของชั้นก็ควรใช้ namespace java.langของตัวเองไม่ได้ การใช้คำพ้องความหมายดังกล่าวเป็นการกระทำที่ไม่ดี
Pacerier

9

นี้บทความจะมีประโยชน์สุดที่จะเข้าใจแข็งแรงนุ่มอ่อนแอและผีอ้างอิง


เพื่อให้คุณสรุป

หากคุณมีการอ้างอิงอ่อนไปยังวัตถุ (โดยไม่มีการอ้างอิงที่แข็งแกร่ง) ดังนั้น GC จะเรียกคืนวัตถุในรอบ GC ถัดไป

หากคุณมีการอ้างอิงที่นุ่มนวลไปยังวัตถุ (โดยไม่มีการอ้างอิงที่รัดกุม) วัตถุนั้นจะถูกเรียกคืนโดย GC เฉพาะเมื่อ JVM มีหน่วยความจำไม่เพียงพอ


ดังนั้นคุณสามารถพูดได้ว่าการอ้างอิงที่แข็งแกร่งมีพลังอำนาจสูงสุด (ไม่สามารถรวบรวมได้โดย GC)

ซอฟท์อ้างอิงมีประสิทธิภาพมากกว่าการอ้างอิงที่อ่อนแอ (เพราะพวกเขาสามารถหลบหนีวงจร GC จนกระทั่ง JVM หมดหน่วยความจำ)

การอ้างอิงที่อ่อนแอนั้นมีประสิทธิภาพน้อยกว่าการอ้างอิงแบบนุ่มนวล (เนื่องจากไม่สามารถ excape รอบ GC ใด ๆ และจะถูกเรียกคืนหากวัตถุไม่มีการอ้างอิงที่แข็งแกร่งอื่น ๆ )


ร้านอาหารคล้ายคลึง

  • พนักงานเสิร์ฟ - GC
  • คุณ - วัตถุในกอง
  • พื้นที่ร้านอาหาร / พื้นที่ - พื้นที่กอง
  • ลูกค้าใหม่ - วัตถุใหม่ที่ต้องการโต๊ะในร้านอาหาร

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

หากคุณเป็นลูกค้าที่อ่อนนุ่ม (คล้ายกับการอ้างอิงที่อ่อนนุ่ม) ดังนั้นหากมีลูกค้าใหม่เข้ามาในร้านอาหารพนักงานเสิร์ฟจะไม่ขอให้คุณออกจากโต๊ะเว้นแต่จะไม่มีโต๊ะว่างเหลืออยู่เพื่อรองรับลูกค้าใหม่ (กล่าวอีกนัยหนึ่งพนักงานเสิร์ฟจะขอให้คุณออกจากโต๊ะเฉพาะเมื่อมีลูกค้าใหม่เข้ามาและไม่มีโต๊ะเหลือสำหรับลูกค้าใหม่นี้)

หากคุณเป็นลูกค้าที่อ่อนแอ (คล้ายกับการอ้างอิงที่อ่อนแอ) พนักงานเสิร์ฟตามความประสงค์ของเขาสามารถ (เมื่อใดก็ได้) ขอให้คุณออกจากร้านอาหาร: P


7

ความแตกต่างที่แท้จริงเท่านั้น

ต่อเอกสารจะต้องทำการล้างWeakReferences ที่หลวมโดย GC ที่กำลังรันอยู่

ตามเอกสารจะต้องล้างSoftReferences ที่หลวมก่อนที่จะมีการโยน OOM

นั่นคือความแตกต่างที่แท้จริงเท่านั้น ทุกอย่างอื่นไม่ได้เป็นส่วนหนึ่งของสัญญา (ฉันจะถือว่าเอกสารล่าสุดเป็นสัญญา)

SoftReferences มีประโยชน์ แคชที่ไวต่อหน่วยความจำใช้ SoftReferences ไม่ใช่ WeakReferences


การใช้ WeakReference ที่เหมาะสมเพียงอย่างเดียวคือการสังเกตการทำงานของ GC คุณทำเช่นนี้โดยการสร้าง WeakReference ใหม่ที่มีวัตถุทันทีไปจากขอบเขตแล้วพยายามที่จะได้รับ null weak_ref.get()ออกจาก เมื่อเป็นnullเช่นนั้นคุณจะได้เรียนรู้ว่าระหว่างช่วงเวลานี้ GC ทำงาน

สำหรับการใช้ WeakReference ที่ไม่ถูกต้องรายการจะไม่มีที่สิ้นสุด:

  • แฮ็คที่น่าสงสารที่จะใช้ซอฟต์เรนเดอร์ลำดับความสำคัญ -2 ซึ่งคุณไม่ต้องเขียนแต่มันก็ไม่ได้ผลอย่างที่คาดไว้เพราะแคชจะถูกล้างในทุกการรันของ GC แม้ว่าจะมีหน่วยความจำสำรอง ดู https://stackoverflow.com/a/3243242/632951สำหรับ phails (นอกจากนี้แล้วถ้าคุณต้องการลำดับความสำคัญแคชมากกว่า 2 ระดับคุณจะต้องมีไลบรารี่จริงด้วย)

  • แฮ็คหมัดเพื่อเชื่อมโยงข้อมูลกับวัตถุของคลาสที่มีอยู่แต่มันสร้างหน่วยความจำรั่ว (OutOfMemoryError) เมื่อ GC ของคุณตัดสินใจที่จะหยุดพักหลังจากสร้างจุดอ่อนของคุณ นอกจากนี้มันเกินกว่าน่าเกลียด: วิธีที่ดีกว่าคือการใช้สิ่งอันดับ

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


สิ่งที่เกี่ยวกับแคชที่ประเภทของคีย์equals()เป็นเพียงตัวตนของวัตถุ? การอ้างอิงที่นุ่มนวลดูเหมือนของเสียที่นั่นเพราะเมื่อวัตถุสำคัญไม่สามารถเข้าถึงได้อีกต่อไปไม่มีใครที่จะค้นหาการทำแผนที่นั้นอีกครั้ง
HighCommander4

ฉันไม่เห็นด้วย. ใช้ WeakReference เมื่อคุณไม่ต้องการมีอิทธิพลต่อ GC ในตัวต่อไป (คุณอาจต้องการบันทึกการอ้างอิงวัตถุจากนั้นตรวจสอบในภายหลังว่ายังมีอยู่หรือไม่โดยไม่ต้องมีการตั้งค่าใด ๆ ) ใช้ SoftReference หากคุณต้องการให้ GC พยายามและเก็บวัตถุ (เช่นเมื่อคุณต้องการให้ GC เก็บไว้)
David Refaeli

ตัวอย่างที่ดีที่จะใช้ WeakReference อยู่ใน AsyncTask ของ Android เพื่อเก็บตัวอย่างของบริบท ด้วยวิธีนี้ถ้าบริบทตาย (หากกิจกรรม - การหมุนหน้าจอ ฯลฯ ) AsyncTask จะไม่มีการอ้างอิงที่แข็งแกร่งใด ๆ ดังนั้นจึงสามารถรวบรวมขยะได้ ตรวจสอบyoutu.be/…
David Refaeli

3

สถานะการเข้าถึงวัตถุหกชนิดใน Java:

  1. แข็งแกร่งวัตถุเข้าถึง Ly - GC จะไม่เก็บ ( เรียกคืนหน่วยความจำที่ถูกครอบครองโดย ) ชนิดของวัตถุนี้ สิ่งเหล่านี้สามารถเข้าถึงได้ผ่านทางรูทโหนดหรือวัตถุอื่นที่เข้าถึงได้มาก (เช่นผ่านตัวแปรโลคอลตัวแปรคลาสตัวแปรอินสแตนซ์ ฯลฯ )
  2. วัตถุที่เข้าถึงได้อย่างนุ่มนวล - GC อาจพยายามรวบรวมวัตถุประเภทนี้ขึ้นอยู่กับการแข่งขันของหน่วยความจำ สิ่งเหล่านี้สามารถเข้าถึงได้จากรูทผ่านวัตถุอ้างอิงที่อ่อนนุ่มอย่างน้อยหนึ่งรายการ
  3. วัตถุที่สามารถเข้าถึงได้อ่อนแอ - GC ต้องรวบรวมวัตถุประเภทนี้ สามารถเข้าถึงได้จากรูทผ่านออบเจ็กต์อ้างอิงที่อ่อนแออย่างน้อยหนึ่งรายการ
  4. วัตถุที่สามารถคืนชีพได้ - GC อยู่ในกระบวนการรวบรวมวัตถุเหล่านี้แล้ว แต่พวกเขาอาจกลับไปที่หนึ่งในรัฐ - Strong / Soft / Weakโดยการดำเนินการของ finalizer
  5. ออบเจ็กต์ที่เข้าถึงได้ของPhantom ly - GC อยู่ในขั้นตอนการรวบรวมวัตถุเหล่านี้แล้วและได้ตัดสินใจที่จะไม่สามารถกู้คืนได้โดยผู้ใช้งานคนสุดท้าย สิ่งเหล่านี้สามารถเข้าถึงได้จากรูทผ่านวัตถุอ้างอิงผีหนึ่งรายการหรือมากกว่า
  6. วัตถุที่ไม่สามารถเข้าถึงได้ - วัตถุนั้นไม่สามารถเข้าถึงได้อย่างรุนแรงนุ่มนวลหรืออ่อนแอและไม่สามารถฟื้นคืนชีพได้ วัตถุเหล่านี้พร้อมสำหรับการกู้คืน

สำหรับรายละเอียดเพิ่มเติม: https://www.artima.com/insidejvm/ed2/gc16.html «ยุบ


4
ไม่ใช่คำอธิบายที่ดีเกี่ยวกับการอ้างอิงแฝง นอกจากนี้คุณยังได้ระบุไว้ 4 ประเภทตามลำดับที่แปลกประหลาด "phantom" เป็นประเภทที่อ่อนแอที่สุดไม่ใช่ประเภทที่แข็งแกร่งที่สุด ลำดับดั้งเดิมในการแสดงรายการเหล่านี้คือ "strong, soft, อ่อนแอ, phantom" และฉันไม่ทราบว่าคุณมีความคิดอย่างไรว่าวัตถุแฝงนั้นใช้สำหรับกลไกการแคช AFAIK พวกเขาเป็นสถานะชั่วคราวที่เห็นโดย GC เท่านั้นไม่ใช่สิ่งที่โปรแกรมเมอร์ธรรมดาจะทำงานด้วย
ToolmakerSteve

@ToolmakerSteve และทั้งหมด - ขอโทษสำหรับบางสิ่ง 1. คำอธิบายที่ผิดพลาดของ Phantom Reference ในคำตอบของฉันในเวอร์ชันก่อนหน้านี้และ 2. ล่าช้าในการแก้ไขข้อผิดพลาด ขณะนี้คำตอบได้รับการปรับปรุงโดยแก้ไขข้อผิดพลาด
V.Vidyasagar

1

เราควรทราบว่าวัตถุที่อ้างอิงอย่างอ่อนจะได้รับการรวบรวมเมื่อมันมีการอ้างอิงที่อ่อนแอเท่านั้น ถ้ามันมีการอ้างอิงที่รัดกุมมาก ๆ มันจะไม่ได้รับการรวบรวมไม่ว่าจะมีการอ้างอิงที่อ่อนแอเท่าใด


นี่คือสามัญสำนึก ... ไปเหมือนกันสำหรับ softref และ phantomref
Pacerier

1

เพื่อให้การใช้งานหน่วยความจำแบบแอ็คชั่นฉันได้ทำการทดลองกับการอ้างอิงแบบ Strong, Soft, Weak & Phantom ภายใต้การใช้งานจำนวนมากที่มีวัตถุหนักโดยการเก็บไว้จนถึงตอนท้ายของโปรแกรม จากนั้นตรวจสอบการใช้งานกองและพฤติกรรม GC ตัวชี้วัดเหล่านี้อาจแตกต่างกันไปในแต่ละกรณี แต่ให้ความเข้าใจในระดับสูงอย่างแน่นอน ด้านล่างนี้เป็นข้อค้นพบ

Heap & GC Behavior ภายใต้ภาระหนัก

  • การอ้างอิงที่รัดกุม / ยาก - เมื่อโปรแกรมดำเนินการต่อ JVM ไม่สามารถรวบรวมออบเจ็กต์อ้างอิงที่ถูกเก็บรักษาไว้อย่างแน่นหนา ในที่สุดก็จบลงใน "java.lang.OutOfMemoryError: Java heap space"
  • Soft Reference - เมื่อโปรแกรมดำเนินต่อไปการใช้งานฮีปยังเพิ่มขึ้นเรื่อย ๆ แต่ OLD gen GC เกิดขึ้นเมื่อใกล้ถึงฮีปสูงสุด GC เริ่มบิตในเวลาต่อมาหลังจากเริ่มโปรแกรม
  • Weak Reference - เมื่อโปรแกรมเริ่มต้นวัตถุก็เริ่มทำการสรุปและรวบรวมได้เกือบจะทันที วัตถุส่วนใหญ่ถูกรวบรวมในการรวบรวมขยะรุ่นใหม่
  • การอ้างอิงผี - คล้ายกับการอ้างอิงที่อ่อนแอวัตถุอ้างอิงผีก็เริ่มได้รับการสรุปและรวบรวมขยะทันที ไม่มี GC รุ่นเก่าและวัตถุทั้งหมดถูกรวบรวมในการรวบรวมขยะรุ่นใหม่

คุณสามารถรับกราฟเชิงลึกสถิติการสังเกตการณ์สำหรับการทดสอบนี้ได้มากขึ้นที่นี่


0

WeakReference : วัตถุที่อ้างอิงอย่างอ่อนเท่านั้นจะถูกรวบรวมในทุก ๆ รอบของ GC (เล็กน้อยหรือเต็ม)

SoftReference : เมื่อรวบรวมวัตถุที่มีการอ้างอิงอย่างนุ่มนวลเท่านั้นจะถูกรวบรวมขึ้นอยู่กับ:

  1. -XX: SoftRefLRUPolicyMSPerMB = N แฟล็ก (ค่าเริ่มต้นคือ 1,000, aka 1 วินาที)

  2. จำนวนหน่วยความจำว่างในกอง

    ตัวอย่าง:

    • ฮีปมีพื้นที่ว่าง 10MB (หลังจากเต็ม GC)
    • -XX: SoftRefLRUPolicyMSPerMB = 1000

    จากนั้นวัตถุที่ถูกอ้างอิงโดย SoftReference เท่านั้นจะถูกรวบรวมหากครั้งล่าสุดที่มีการเข้าถึงมากกว่า 10 วินาที

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