จำเป็นต้องใช้ autoreleasepool ในโปรแกรม Swift หรือไม่?


97

ในหน้า 17 ของงานนำเสนอ WWDC14 นี้มีข้อความว่า

การทำงานกับ Objective-C? ยังต้องจัดการ autoreleasepool พูลการปล่อยอัตโนมัติ
{/ * code * /}

นั่นหมายความว่าอย่างไร? หมายความว่าถ้าฐานรหัสของฉันไม่มีไฟล์ Objective-C autoreleasepool {}ก็ไม่จำเป็น?

ในคำตอบของคำถามที่เกี่ยวข้องมีตัวอย่างที่autoreleasepoolสามารถเป็นประโยชน์:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

หากโค้ดด้านบนได้รับการแปลเป็น Swift พร้อมกับautoreleasepoolหลุด Swift จะฉลาดพอที่จะรู้ว่าnumberควรปล่อยตัวแปรหลังจากตัวแรก}(เช่นเดียวกับภาษาอื่น ๆ ) หรือไม่


1
ดูเหมือนจะไม่มีเอกสารประกอบautoreleasepoolใน Swift ผมขยายตัวในคำถามของคุณและถามในฟอรั่มที่ dev
Aaron Brager

คำตอบ:


204

autoreleasepoolรูปแบบที่ใช้ในสวิฟท์เมื่อกลับautoreleaseวัตถุ (ที่สร้างขึ้นโดยทั้งรหัส Objective-C หรือการใช้การเรียนโกโก้) autoreleaseในรูปแบบฟังก์ชั่นสวิฟท์เหมือนมันไม่ใน Objective-C ตัวอย่างเช่นพิจารณาการแสดงผลอย่างรวดเร็วของวิธีการของคุณ (การสร้างอินสแตนซ์NSImage/ UIImageวัตถุ):

func useManyImages() {
    let filename = pathForResourceInBundle

    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

หากคุณเรียกใช้สิ่งนี้ในเครื่องมือคุณจะเห็นกราฟการจัดสรรดังต่อไปนี้:

ด้วย autoreleasepool

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

ไม่มี autoreleasepool

autoreleasepoolช่วยให้คุณจัดการอย่างชัดเจนเมื่อวัตถุ autorelease จะ deallocated ในสวิฟท์เช่นเดียวกับคุณก็สามารถที่จะอยู่ใน Objective-C

หมายเหตุ: เมื่อจัดการกับวัตถุเนทีฟของ Swift โดยทั่วไปคุณจะไม่ได้รับออบเจ็กต์การปล่อยอัตโนมัติ นี่คือเหตุผลที่งานนำเสนอกล่าวถึงข้อแม้ที่ว่าต้องการสิ่งนี้เมื่อ "ทำงานกับ Objective-C" เท่านั้น แต่ฉันหวังว่า Apple จะชัดเจนมากขึ้นในประเด็นนี้ แต่ถ้าคุณกำลังจัดการกับ Objective-C object (รวมถึงคลาส Cocoa) พวกมันอาจเป็นอ็อบเจ็กต์ autorelease ซึ่งในกรณีนี้การแสดงผล Swift ของ@autoreleasepoolรูปแบบObjective-C ยังคงมีประโยชน์


2
สำหรับคำถามเหล่านี้คุณสามารถเขียนชั้นเรียนของคุณเองและให้ทำprintlnในdeinitและจะค่อนข้างง่ายในการตรวจสอบอย่างแม่นยำเมื่อมีการยกเลิกการจัดสรรออบเจ็กต์ หรือสังเกตในตราสาร ในคำตอบสำหรับคำถามของคุณดูเหมือนว่าวัตถุ Swift จะถูกส่งคืนจากฟังก์ชันที่มีจำนวนคงที่ +1 (ไม่ใช่อ็อบเจ็กต์การปลดปล่อยอัตโนมัติ) และผู้โทรจะจัดการความเป็นเจ้าของจากจุดนั้นได้อย่างราบรื่น (เช่นหากและเมื่อวัตถุที่ส่งคืนอยู่นอกขอบเขต จะถูกยกเลิกการจัดสรรทันทีไม่ได้วางไว้ใน autoreleasepool)
Rob

3
@StevenHernandez กลุ่ม autorelease มีส่วนเกี่ยวข้องกับการรั่วไหลน้อยมาก การรั่วไหลเกิดจากวัตถุที่ยังไม่ได้เปิดตัว ในทางกลับกันกลุ่ม Autorelease เป็นเพียงคอลเลกชันของอ็อบเจ็กต์ที่รีลีสถูกเลื่อนออกไปจนกว่าพูลจะถูกระบายออก พูลไม่ได้ควบคุมว่าจะมีการจัดสรรบางอย่างหรือไม่ แต่เป็นเพียงช่วงเวลาของการจัดสรรดังกล่าว มุมมองแผนที่อีกครั้งคุณไม่สามารถควบคุมสิ่งที่แคชทำ (ใช้หน่วยความจำ แต่ไม่ใช่การรั่วไหลจริง) และไม่ทำอะไรเลยหากมีการรั่วไหลจริง (และฉันไม่ทราบว่ามีการรั่วไหลของมุมมองแผนที่ที่สำคัญใด ๆ แม้ว่าในอดีตจะมี การรั่วไหลแบบสุ่มและเล็กน้อยใน UIKit)
Rob

2
@matt เย้ ๆ เห็นพฤติกรรมคล้าย ๆ กัน ดังนั้นฉันจึงทำแบบฝึกหัดซ้ำกับNSImage/ UIImageobject และแสดงให้เห็นปัญหาอย่างสม่ำเสมอมากขึ้น (และตรงไปตรงมานี่เป็นตัวอย่างของปัญหาที่พบบ่อยเนื่องจากการใช้หน่วยความจำสูงสุดมักเป็นปัญหาเฉพาะเมื่อต้องจัดการกับวัตถุขนาดใหญ่เท่านั้นตัวอย่างที่ใช้ได้จริงของสิ่งนี้อาจเป็น กิจวัตรการปรับขนาดภาพจำนวนมาก) ฉันยังจำลองพฤติกรรมการเรียกใช้รหัส Objective-C ที่สร้างอ็อบเจ็กต์การปลดปล่อยอัตโนมัติอย่างชัดเจน อย่าเข้าใจฉันผิด: ฉันคิดว่าเราต้องการกลุ่มการปล่อยอัตโนมัติใน Swift น้อยกว่าใน Objective-C แต่ก็ยังมีบทบาทในการเล่น
Rob

1
เจอตัวอย่างที่ใช้ได้! เพียงแค่เรียก NSBundle pathForResource:ofType:ซ้ำ ๆ
แมต

1
pathForResource:ofType:ตัวอย่างของฉันใช้ไม่ได้ใน Xcode 6.3 / Swift 1.2 อีกต่อไป :)
แมตต์

5

หากคุณจะใช้ในรหัส Objective-C ที่เทียบเท่าคุณจะใช้ใน Swift

Swift จะฉลาดพอที่จะรู้ว่าควรปล่อยตัวแปร number หลังจากครั้งแรก}

เฉพาะในกรณีที่ Objective-C ทำเท่านั้น ทั้งสองดำเนินการตามกฎการจัดการหน่วยความจำโกโก้

แน่นอนว่า ARC รู้ว่าnumberมันอยู่นอกขอบเขตเมื่อสิ้นสุดการวนซ้ำนั้นและถ้ามันยังคงอยู่มันจะปล่อยมันออกไปที่นั่น อย่างไรก็ตามนั่นไม่ได้บอกคุณว่าวัตถุนั้นถูกปล่อยอัตโนมัติ-[NSNumber numberWithInt:] หรือไม่เนื่องจากอาจส่งคืนอินสแตนซ์ที่ปล่อยอัตโนมัติหรือไม่ ไม่มีทางที่คุณจะรู้ได้เนื่องจากคุณไม่สามารถเข้าถึงแหล่งที่มาของ-[NSNumber numberWithInt:]ไฟล์.


1
หาก Swift ทำงานเหมือนกับ Objective-C สำหรับสิ่งนี้เหตุใดการนำเสนอจึงกล่าวถึง "Working with Objective-C?" โดยเฉพาะ?
Ethan

9
@ Ethan ดูเหมือนว่าวัตถุ Swift ดั้งเดิมไม่ใช่วัตถุปล่อยอัตโนมัติและautoreleasepoolโครงสร้างไม่จำเป็นโดยสิ้นเชิง แต่ถ้าโค้ด Swift ของคุณจัดการกับ Objective-C object (รวมถึงวัตถุ Cocoa) สิ่งเหล่านั้นจะเป็นไปตามรูปแบบการปล่อยอัตโนมัติดังนั้นautoreleasepoolโครงสร้างจึงมีประโยชน์
Rob

ฉันเข้าใจว่า "Autoreleasepool ช่วยให้คุณจัดการได้อย่างชัดเจนเมื่อมีการยกเลิกการจัดสรรวัตถุอัตโนมัติใน Swift" แต่ทำไมฉันถึงต้องการ ทำไมคอมไพเลอร์ไม่ / ไม่ทำเพื่อฉัน ฉันต้องเพิ่ม autoreleasepool ของตัวเองเพื่อป้องกันไม่ให้ VM ผ่านหลังคาในการปรับแต่งสตริงขนาดใหญ่ เห็นได้ชัดว่าควรเพิ่มตรงไหนและทำงานได้ดี ทำไมคอมไพเลอร์ถึงทำไม่ได้? คอมไพเลอร์จะฉลาดขึ้นเพื่อทำงานที่ดีได้หรือไม่?
vonlost
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.