รูปแบบการนับการอ้างอิงสำหรับภาษาที่มีการจัดการหน่วยความจำ?


11

Java และ. NET มีตัวรวบรวมขยะที่ยอดเยี่ยมที่จัดการหน่วยความจำสำหรับคุณและรูปแบบที่สะดวกสำหรับการปล่อยวัตถุภายนอก ( Closeable, IDisposable) ได้อย่างรวดเร็วแต่เฉพาะในกรณีที่พวกเขาเป็นเจ้าของวัตถุเดียว ในบางระบบทรัพยากรอาจจำเป็นต้องใช้อย่างอิสระโดยสององค์ประกอบและจะได้รับการปล่อยตัวก็ต่อเมื่อทั้งสององค์ประกอบปล่อยทรัพยากร

ใน C ++ ยุคใหม่คุณจะแก้ปัญหานี้ด้วย a shared_ptrซึ่งจะปล่อยทรัพยากรอย่างแน่นอนเมื่อทุกอย่างshared_ptrถูกทำลาย

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


1
คุณจะได้เห็นเสียงดังกราวอ้างอิงอัตโนมัตินับนอกจากนี้ยังใช้ในสวิฟท์ ?
jscs

1
@ JoshCaswell ใช่แล้วและนั่นจะช่วยแก้ปัญหาได้ แต่ฉันกำลังทำงานในพื้นที่เก็บขยะ
C. Ross

8
การนับการอ้างอิงเป็นกลยุทธ์การรวบรวมขยะ
Jörg W Mittag

คำตอบ:


15

โดยทั่วไปแล้วคุณควรหลีกเลี่ยงโดยการมีเจ้าของคนเดียว - แม้ในภาษาที่ไม่มีการจัดการ

แต่หลักการเหมือนกันสำหรับภาษาที่ได้รับการจัดการ แทนการปิดทรัพยากรที่มีราคาแพงในทันทีเมื่อClose()คุณลดจำนวนตัวนับ (เพิ่มขึ้นในOpen()/ Connect()/ ฯลฯ ) จนกว่าคุณจะกด 0 ณ จุดที่การปิดทำการปิดจริง มันน่าจะมีรูปลักษณ์และทำตัวเหมือน Flyweight Pattern


นี่คือสิ่งที่ฉันคิดเช่นกัน แต่มีรูปแบบการบันทึกไว้หรือไม่ Flyweight นั้นคล้ายกัน แต่โดยเฉพาะสำหรับหน่วยความจำตามปกติ
C. Ross

@ C.Ross นี่เป็นกรณีที่ได้รับการสนับสนุนเข้ารอบสุดท้าย คุณสามารถใช้คลาส wrapper รอบ ๆ รีซอร์สที่ไม่มีการจัดการเพิ่ม finalizer ให้กับคลาสนั้นเพื่อปล่อยรีซอร์ส นอกจากนี้คุณยังสามารถใช้งานได้IDisposableนับจำนวนที่จะปล่อยทรัพยากรโดยเร็วที่สุด ฯลฯ อาจเป็นสิ่งที่ดีที่สุดหลายครั้งคือการมีทั้งสามอย่าง แต่ตัวสุดท้ายอาจเป็นส่วนที่สำคัญที่สุดและIDisposableการนำไปใช้คือ สำคัญน้อยที่สุด
Panzercrisis

11
@Panzercrisis ยกเว้น finalizers ที่ไม่ได้รับประกันว่าจะวิ่งและโดยเฉพาะอย่างยิ่งไม่รับประกันว่าจะทำงานทันที
Caleth

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


14

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

แนวคิดของ“ การเป็นเจ้าของทรัพยากร” ไม่ได้ใช้จริงในภาษา GC ระบบ GC เป็นเจ้าของวัตถุทั้งหมด

สิ่งที่ภาษาเหล่านี้มีให้กับ try-with-resource + Closeable (Java) โดยใช้ statement + IDisposable (C #) หรือกับ statement + context managers (Python) เป็นวิธีการควบคุมโฟลว์ (! = วัตถุ) เพื่อเก็บทรัพยากรที่ ถูกปิดเมื่อโฟลว์การควบคุมออกจากขอบเขต try { ... } finally { resource.close(); }ในทุกกรณีเหล่านี้เป็นคล้ายกับแทรกโดยอัตโนมัติ อายุการใช้งานของวัตถุที่แสดงถึงทรัพยากรไม่เกี่ยวข้องกับอายุการใช้งานของทรัพยากร: วัตถุอาจยังคงอยู่หลังจากที่ปิดทรัพยากรและวัตถุอาจไม่สามารถเข้าถึงได้ในขณะที่ทรัพยากรยังคงเปิดอยู่

ในกรณีของตัวแปรท้องถิ่นวิธีการเหล่านี้เทียบเท่ากับ RAII แต่ต้องใช้อย่างชัดเจนที่ไซต์การโทร (ไม่เหมือน C ++ destructors ซึ่งจะทำงานตามค่าเริ่มต้น) IDE ที่ดีจะเตือนเมื่อมีการละเว้น

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

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

สิ่งนี้ถือว่าเป็นทางออกที่ทำงานได้เพียงอย่างเดียว: การจัดการทรัพยากรด้วยตนเอง นี่เป็นข้อผิดพลาดได้ง่าย แต่เป็นไปไม่ได้ โดยเฉพาะอย่างยิ่งการคิดเกี่ยวกับความเป็นเจ้าของนั้นผิดปกติในภาษา GC ดังนั้นรหัสที่มีอยู่อาจไม่ชัดเจนเพียงพอเกี่ยวกับการรับประกันความเป็นเจ้าของ


3

ข้อมูลที่ดีมากมายจากคำตอบอื่น ๆ

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

ดังนั้นจึงมีวัตถุเจ้าของเดี่ยวขนาดเล็กที่ไม่ได้แชร์ซึ่ง (ผ่านทางวัตถุที่เล็กกว่าIDisposeและโครงสร้างusingการควบคุมการไหล) สามารถแจ้งให้ทราบถึงวัตถุที่ใช้ร่วมกันที่มีขนาดใหญ่กว่า (อาจกำหนดเองAcquire& Releaseวิธีการ)

( AcquireและReleaseวิธีการที่แสดงด้านล่างนี้ยังมีอยู่นอกการใช้งานการสร้าง แต่ไม่มีความปลอดภัยtryโดยนัยusing)


ตัวอย่างใน C #

void Test ( MyRefCountedClass myObj )
{
    using ( var usingRef = myObj.Acquire () )
    {
        var item = usingRef.Item;
        item.SomeMethod ();

        // the `using` automatically invokes Dispose() on usingRef
        //  which in turn invokes Release() on `myObj.
    }
}

interface IReferencable<T> where T: IReferencable<T> {
    Reference<T> Acquire ();
    void Release();
}

struct Reference<T>: IDisposable where T: IReferencable<T>
{
    public readonly T Item;
    public Reference(T item) { Item = item; _released = false; }
    public void Dispose() { if (! _released ) { _released = true; Item.Release(); } }
    private bool _released;
}

class MyRefCountedClass : IReferencable<MyRefCountedClass>
{
    private int _refCount = 0;

    public Reference<MyRefCountedClass> Acquire ()
    {
        _refCount++;
        return new Reference<MyRefCountedClass>(this);
    }

    public void Release ()
    {
        if (--_refCount <= 0)
            Dispose();
    }

    // NOTE that MyRefCountedClass does not have to implement IDisposable, but it can...
    // as shown here it doesn't implement the interface
    private void Dispose ()  
    {
        if ( _refCount > 0 )
            throw new Exception ("Dispose attempted on item in use.");
        // release other resources...
    }

    public int SomeMethod()
    {
        return 0;
    }
}

หากเป็น C # (ซึ่งดูเหมือน) การอ้างอิง <T> ของคุณจะไม่ถูกต้องอย่างละเอียด สัญญาสำหรับIDisposable.Disposeรัฐที่เรียกDisposeหลายครั้งบนวัตถุเดียวกันจะต้องเป็นแบบไม่มี ถ้าฉันจะใช้รูปแบบดังกล่าวฉันก็จะทำให้เป็นReleaseส่วนตัวเพื่อหลีกเลี่ยงข้อผิดพลาดที่ไม่จำเป็นและใช้การมอบหมายแทนการสืบทอด (เอาส่วนต่อประสานออกให้SharedDisposableชั้นเรียนอย่างง่าย ๆที่สามารถใช้กับ Disposables โดยพลการ)
Voo

@ Voo, ok, จุดดีขอบคุณ!
Erik Eidt

1

วัตถุส่วนใหญ่ในระบบโดยทั่วไปควรจะพอดีกับหนึ่งในสามรูปแบบ:

  1. วัตถุที่รัฐจะไม่เปลี่ยนแปลงและการอ้างอิงที่ถูกถือไว้อย่างหมดจดเป็นวิธีการห่อหุ้มรัฐ เอนทิตีที่เก็บการอ้างอิงไม่รู้หรือสนใจว่าเอนทิตีอื่นใดถือการอ้างอิงไปยังวัตถุเดียวกัน

  2. วัตถุที่อยู่ภายใต้การควบคุมพิเศษของกิจการเดียวซึ่งเป็นเจ้าของ แต่เพียงผู้เดียวของทุกรัฐในนั้นและใช้วัตถุนั้นเป็นเครื่องมือในการห่อหุ้มสถานะ (อาจจะไม่แน่นอน) ในนั้น

  3. วัตถุที่เป็นของเอนทิตีเดียว แต่เอนทิตีอื่น ๆ ที่ได้รับอนุญาตให้ใช้ในวิธีที่ จำกัด เจ้าของวัตถุอาจใช้มันไม่เพียง แต่เป็นวิธีการห่อหุ้มของรัฐ แต่ยังห่อหุ้มความสัมพันธ์กับหน่วยงานอื่นที่ใช้ร่วมกัน

การติดตามการรวบรวมขยะทำงานได้ดีกว่าการอ้างอิงการอ้างอิงสำหรับ # 1 เนื่องจากรหัสที่ใช้วัตถุดังกล่าวไม่จำเป็นต้องทำอะไรเป็นพิเศษเมื่อเสร็จสิ้นการอ้างอิงที่เหลือล่าสุด ไม่จำเป็นต้องมีการนับการอ้างอิงสำหรับ # 2 เพราะวัตถุจะมีเจ้าของคนเดียวและจะรู้เมื่อไม่ต้องการวัตถุอีกต่อไป สถานการณ์สมมติ # 3 อาจมีปัญหาบางอย่างหากเจ้าของวัตถุฆ่ามันในขณะที่หน่วยงานอื่นยังคงมีการอ้างอิง แม้ว่าจะมีการติดตาม GC อาจดีกว่าการนับการอ้างอิงเพื่อให้แน่ใจว่าการอ้างอิงไปยังวัตถุที่ตายแล้วยังคงสามารถระบุตัวตนได้อย่างน่าเชื่อถือว่าเป็นการอ้างอิงไปยังวัตถุที่ตายแล้วตราบเท่าที่การอ้างอิงนั้นมีอยู่

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


0

ความเป็นเจ้าของร่วมกันไม่ค่อยมีเหตุผล

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

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

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

การรั่วไหลของทรัพยากร

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

และสิ่งเหล่านี้ไม่ใช่การรั่วไหลของทรัพยากรเล็กน้อยที่ทำให้นักพัฒนารู้สึกหงุดหงิดเช่นเดียวกับหน่วยความจำหนึ่งกิโลไบต์ที่รั่วไหลออกมาหลังจากผ่านไปหนึ่งชั่วโมง นี่คือการรั่วไหลครั้งยิ่งใหญ่ซึ่งมักจะมีหน่วยความจำกิกะไบต์ในเซสชันที่ใช้งานอยู่ซึ่งนำไปสู่การรายงานบั๊ก เพราะตอนนี้เมื่อมีการอ้างอิงความเป็นเจ้าของทรัพยากร (และแบ่งปันในกรรมสิทธิ์) ดังนั้นพูดว่า 8 ส่วนต่าง ๆ ของระบบจากนั้นจะใช้เวลาเพียงหนึ่งล้มเหลวในการลบทรัพยากรในการตอบสนองต่อผู้ใช้ที่ร้องขอให้ลบมันสำหรับมัน ที่จะรั่วไหลออกไปและอาจเป็นไปอย่างไม่มีกำหนด

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

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

วิธีแก้ไข: เลื่อนออกเป็นระยะ ๆ

ดังนั้นวิธีการแก้ปัญหาของฉันในภายหลังซึ่งผมนำไปใช้กับโครงการส่วนบุคคลของฉันที่ให้ฉันชนิดของดีที่สุดที่ฉันพบจากโลกทั้งสองคือการขจัดแนวคิดว่าreferencing=ownershipแต่ยังคงมีการทำลายรอการตัดบัญชีของทรัพยากร

ดังนั้นเมื่อใดก็ตามที่ผู้ใช้ทำบางสิ่งที่ทำให้ทรัพยากรต้องการการลบ API จะแสดงในแง่ของการลบทรัพยากรออก:

ecs->remove(component);

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

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

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

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

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