โมเดลหน่วยความจํา J2ObjC

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

การจัดการหน่วยความจำ

หนึ่งในเป้าหมายของ J2ObjC คือการสร้างโค้ดที่แปลแล้ว ซึ่งจะผสานรวมเข้ากับสภาพแวดล้อมการนับข้อมูลอ้างอิงของ Objective-C อย่างราบรื่น วิธีนี้จะช่วยให้โค้ด Java ที่แปลแล้วใช้งานจาก Objective-C ที่เขียนขึ้นมาแต่เดิมได้ง่าย เนื่องจากจะไม่มีการโอนการเป็นเจ้าของที่อึดอัดใจสำหรับออบเจ็กต์ที่ส่งผ่านระหว่างสภาพแวดล้อม Java และ Objective-C

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

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

รอบอ้างอิง

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

  • เพิ่มคำอธิบายประกอบ @Weak หรือ @WeakOuter เพื่อลดความซับซ้อนของข้อมูลอ้างอิง
  • เพิ่มเมธอด cleanup() ลงในออบเจ็กต์รายการหนึ่งที่กำหนดให้บางช่องเป็น Null โปรดเรียกใช้ cleanup() ก่อนที่จะทิ้งออบเจ็กต์
  • ออกแบบโค้ดใหม่เพื่อหลีกเลี่ยงการสร้างวงจรการอ้างอิงโดยสิ้นเชิง

หน่วยความจำที่ใช้ร่วมกัน

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

ซิงค์แล้ว

J2ObjC จะจับคู่คีย์เวิร์ด synchronized กับ Objective-C @synchronized โดยตรง

Atomicity

Java รับประกัน Atomicity สําหรับการโหลดและร้านค้าทุกประเภทยกเว้น long และ double ดู JLS-17.7 เนื่องจากข้อยกเว้นของช่อง volatile (ตามที่อธิบายไว้ด้านล่าง) J2ObjC ไม่ได้ให้การดูแลเป็นพิเศษสำหรับการรับประกันการโหลดและจัดเก็บแบบอะตอม ซึ่งมีความหมายดังต่อไปนี้

  • เนื่องจากแพลตฟอร์ม iOS ทั้งหมดเป็นแบบ 32 หรือ 64 บิต การโหลดและการจัดเก็บประเภทพื้นฐานยกเว้น long และ double จึงเป็นแบบอะตอมในอุปกรณ์ 32 บิต และทั้งหมดเป็นอะตอมในระบบ 64 บิต
  • โหลดและการจัดเก็บของประเภทออบเจ็กต์ไม่ใช่แบบอะตอมใน J2ObjC
    • การอัปเดตจำนวนการอ้างอิงโดยอัตโมนัติมีค่าใช้จ่ายสูงเกินไป
    • คุณสร้างช่องวัตถุแบบอะตอมได้ด้วยการประกาศ volatile (ดูด้านล่าง)

ฟิลด์ที่ผันผวน

สำหรับช่อง volatile นั้น Java จะให้ทั้งการเรียงลำดับแบบ Atomicity และการเรียงลำดับที่สอดคล้องกัน (JLS-8.3.1.4) ซึ่งใช้สำหรับการซิงค์ได้ J2ObjC ให้การรับประกันเช่นเดียวกับ Java สำหรับช่อง volatile ทั้งหมด J2ObjC ใช้กลไกต่อไปนี้สำหรับฟิลด์ volatile:

  • ประเภทพื้นฐานจะจับคู่กับประเภทอะตอม c11
    • เช่น volatile int -> _Atomic(jint)
  • ช่องออบเจ็กต์ได้รับการปกป้องด้วยล็อก Mutex ของ pthread (ใช้ Spin Lock ไม่ได้เนื่องจากการกลับลำดับความสำคัญ)
    • จำเป็นต้องมีการยกเว้นร่วมกันเพื่อป้องกันเงื่อนไขการแข่งขันที่มีการนับการอ้างอิง
    • การใช้งานนี้คล้ายกับสมบัติอะตอมของ Objective-C

ประเภทอะตอม

Java มีประเภทอะตอมในแพ็กเกจ java.util.concurrent.atomic ทั้งหมดนี้รองรับใน J2ObjC อย่างสมบูรณ์ด้วยการติดตั้งใช้งานที่กำหนดเอง

ฟิลด์สุดท้าย

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