ในภาษาอย่าง C และ C ++ ในขณะที่ใช้พอยน์เตอร์กับตัวแปรเราต้องการที่ตั้งหน่วยความจำอีกหนึ่งแห่งเพื่อเก็บที่อยู่นั้น ดังนั้นนี่ไม่ใช่ค่าใช้จ่ายหน่วยความจำ? สิ่งนี้ได้รับการชดเชยอย่างไร? พอยน์เตอร์ใช้ในเวลาที่แอปพลิเคชันหน่วยความจำเหลือน้อยหรือไม่?
ในภาษาอย่าง C และ C ++ ในขณะที่ใช้พอยน์เตอร์กับตัวแปรเราต้องการที่ตั้งหน่วยความจำอีกหนึ่งแห่งเพื่อเก็บที่อยู่นั้น ดังนั้นนี่ไม่ใช่ค่าใช้จ่ายหน่วยความจำ? สิ่งนี้ได้รับการชดเชยอย่างไร? พอยน์เตอร์ใช้ในเวลาที่แอปพลิเคชันหน่วยความจำเหลือน้อยหรือไม่?
คำตอบ:
ที่จริงแล้วค่าใช้จ่ายไม่ได้อยู่ในความพิเศษ 4 หรือ 8 ไบต์ที่จำเป็นในการจัดเก็บตัวชี้ พอยน์เตอร์ส่วนใหญ่ใช้สำหรับการจัดสรรหน่วยความจำแบบไดนามิกซึ่งหมายความว่าเราเรียกใช้ฟังก์ชันเพื่อจัดสรรบล็อกหน่วยความจำและฟังก์ชันนี้จะส่งกลับตัวชี้ที่ชี้ไปยังบล็อกหน่วยความจำนั้น บล็อกใหม่นี้ในและของตัวเองหมายถึงค่าใช้จ่ายมาก
ตอนนี้คุณไม่จำเป็นต้องมีส่วนร่วมในการจัดสรรหน่วยความจำเพื่อใช้ตัวชี้: คุณสามารถมีอาร์เรย์ของการint
ประกาศแบบคงที่หรือบนสแต็กและคุณสามารถใช้ตัวชี้แทนดัชนีเพื่อเยี่ยมชมint
s และมันเป็น ทุกอย่างดีและเรียบง่ายและมีประสิทธิภาพ ไม่จำเป็นต้องทำการจัดสรรหน่วยความจำและตัวชี้มักจะใช้พื้นที่ในหน่วยความจำเท่าที่ดัชนีจำนวนเต็มจะทำ
นอกจากนี้โจชัวเทย์เลอร์เตือนเราในความคิดเห็นพอยน์เตอร์ถูกใช้เพื่อส่งบางอย่างโดยการอ้างอิง เช่นstruct foo f; init_foo(&f);
จะจัดสรรฉในกองแล้วโทรกับชี้ไปที่init_foo()
struct
เป็นเรื่องธรรมดามาก (โปรดระวังอย่าส่งพอยน์เตอร์เหล่านั้น "ขึ้น") ใน C ++ คุณอาจเห็นสิ่งนี้ถูกทำโดยใช้ "การอ้างอิง" ( foo&
) แทนที่จะเป็นตัวชี้ แต่การอ้างอิงนั้นไม่มีอะไรนอกจากพอยน์เตอร์ที่คุณอาจไม่เปลี่ยนแปลง จำนวนหน่วยความจำเท่ากัน
แต่เหตุผลหลักที่ว่าทำไมการใช้พอยน์เตอร์จึงใช้สำหรับการจัดสรรหน่วยความจำแบบไดนามิกซึ่งจะทำเพื่อแก้ไขปัญหาที่ไม่สามารถแก้ไขได้ นี่คือตัวอย่างง่ายๆ: ลองจินตนาการว่าคุณต้องการอ่านเนื้อหาทั้งหมดของไฟล์ คุณจะเก็บไว้ที่ไหน หากคุณลองใช้บัฟเฟอร์ขนาดคงที่คุณจะสามารถอ่านไฟล์ที่มีความยาวไม่เกินบัฟเฟอร์นั้นเท่านั้น แต่โดยใช้การจัดสรรหน่วยความจำคุณสามารถจัดสรรหน่วยความจำได้มากเท่าที่จำเป็นในการอ่านไฟล์แล้วดำเนินการอ่าน
นอกจากนี้ C ++ เป็นภาษาเชิงวัตถุและมีบางแง่มุมของ OOP เช่นสิ่งที่เป็นนามธรรมซึ่งสามารถทำได้โดยใช้พอยน์เตอร์ แม้แต่ภาษาอย่าง Java และ C # ก็ ใช้พอยน์เตอร์ได้อย่างกว้างขวางพวกเขาก็ไม่อนุญาตให้คุณจัดการพอยน์เตอร์โดยตรงเพื่อป้องกันไม่ให้คุณทำสิ่งที่เป็นอันตรายกับพวกเขา แต่ถึงกระนั้นภาษาเหล่านี้ก็เริ่มเข้าใจเมื่อคุณ ตระหนักว่าเบื้องหลังทุกอย่างทำได้ด้วยการใช้พอยน์เตอร์
ดังนั้นตัวชี้จะไม่ได้ใช้เฉพาะในเวลาที่สำคัญการใช้งานหน่วยความจำต่ำพวกเขาจะใช้ทุกที่
struct foo f; init_foo(&f);
จะจัดสรรให้f
กับสแต็กจากนั้นโทรinit_foo
ด้วยตัวชี้ไปยังโครงสร้างนั้น นั่นเป็นเรื่องธรรมดามาก (โปรดระวังอย่าส่งตัวชี้ "ขึ้นไป")
malloc
มีค่าใช้จ่ายส่วนหัวที่ต่ำมากขณะที่กลุ่มพวกเขาจัดสรรบล็อกใน "ถัง" ในทางตรงกันข้ามสิ่งนี้แปลเป็นการจัดสรรเกินโดยทั่วไป: คุณขอ 35 ไบต์และรับ 64 (โดยที่คุณไม่รู้) ดังนั้นจึงสิ้นเปลือง 29 ...
ดังนั้นนี่ไม่ใช่ค่าใช้จ่ายหน่วยความจำ?
แน่นอนว่าที่อยู่พิเศษ (โดยทั่วไปคือ 4/8 ไบต์ขึ้นอยู่กับโปรเซสเซอร์)
สิ่งนี้ได้รับการชดเชยอย่างไร?
มันไม่ใช่. หากคุณต้องการการชี้ทางอ้อมที่จำเป็นสำหรับพอยน์เตอร์คุณจะต้องจ่าย
พอยน์เตอร์ใช้ในเวลาที่แอปพลิเคชันหน่วยความจำเหลือน้อยหรือไม่?
ฉันไม่ได้ทำงานที่นั่นมากนัก แต่ฉันจะคิดอย่างนั้น การเข้าถึงตัวชี้เป็นลักษณะพื้นฐานของการเขียนโปรแกรมแอสเซมบลี ต้องใช้หน่วยความจำและการดำเนินการตัวชี้จำนวนเล็กน้อยอย่างรวดเร็ว - แม้ในบริบทของแอปพลิเคชันประเภทนี้
ฉันไม่ได้หมุนแบบเดียวกันกับ Telastyn
globals ระบบในโปรเซสเซอร์ที่ฝังตัวอาจได้รับการแก้ไขด้วยที่อยู่ที่ระบุไว้แบบตายตัว
Globals ในโปรแกรมจะได้รับการจัดการเป็นออฟเซ็ตจากตัวชี้พิเศษที่ชี้ไปยังสถานที่ในหน่วยความจำที่จัดเก็บกลมและสแตติก
ตัวแปรท้องถิ่นจะปรากฏขึ้นเมื่อมีการป้อนฟังก์ชั่นและได้รับการจัดการเป็นออฟเซ็ตจากตัวชี้พิเศษอื่น ๆ ซึ่งมักเรียกว่า "ตัวชี้เฟรม" ซึ่งรวมถึงอาร์กิวเมนต์ของฟังก์ชัน หากคุณระมัดระวังเกี่ยวกับการพุชและป็อปด้วยตัวชี้สแต็กคุณสามารถทำได้โดยใช้ตัวชี้เฟรมและเข้าถึงตัวแปรในตัวเครื่องโดยตรงจากตัวชี้สแต็ก
ดังนั้นคุณจ่ายสำหรับการชี้ทางอ้อมไม่ว่าคุณจะเดินผ่านอาร์เรย์หรือเพียงแค่จับตัวแปรท้องถิ่นหรือระดับโลกที่ไม่มีมาตรฐาน มันขึ้นอยู่กับพอยน์เตอร์ที่แตกต่างกันขึ้นอยู่กับตัวแปรของ kinda รหัสที่คอมไพล์ได้ดีจะเก็บตัวชี้นั้นไว้ใน CPU register แทนที่จะโหลดซ้ำทุกครั้งที่ใช้
ใช่แน่นอน แต่มันเป็นการกระทำที่สมดุล
โดยทั่วไปแอปพลิเคชันหน่วยความจำต่ำจะถูกสร้างขึ้นโดยคำนึงถึงการแลกเปลี่ยนระหว่างค่าใช้จ่ายของตัวแปรตัวชี้สองสามตัวเทียบกับค่าโสหุ้ยของสิ่งที่จะเป็นโปรแกรมขนาดใหญ่ (ที่จะต้องเก็บไว้ในหน่วยความจำโปรดจำไว้!) .
การพิจารณานี้ใช้กับทุกโปรแกรมเพราะไม่มีใครต้องการสร้างความยุ่งเหยิงที่น่าสยดสยองและยุ่งเหยิงด้วยรหัสซ้ำซ้ายขวาและอยู่ตรงกลางนั่นคือขนาดใหญ่กว่ายี่สิบเท่าที่ควรจะเป็น
ในภาษาอย่าง C และ C ++ ในขณะที่ใช้พอยน์เตอร์กับตัวแปรเราต้องการที่ตั้งหน่วยความจำอีกหนึ่งแห่งเพื่อเก็บที่อยู่นั้น ดังนั้นนี่ไม่ใช่ค่าใช้จ่ายหน่วยความจำ?
คุณคิดว่าตัวชี้จะต้องเก็บไว้ นั่นไม่ใช่กรณีเสมอไป ตัวแปรทุกตัวจะถูกเก็บไว้ในที่อยู่หน่วยความจำบางส่วน ว่าคุณมีการประกาศให้เป็นlong
long n = 5L;
นี้จัดสรรที่เก็บข้อมูลสำหรับn
ที่อยู่บางแห่ง เราสามารถใช้ที่อยู่ที่จะทำสิ่งแฟนซีเช่นการจัดการกับส่วนของ*((char *) &n) = (char) 0xFF;
n
ที่อยู่ของn
ไม่ได้เก็บไว้ที่ใดก็ได้เป็นค่าใช้จ่ายเพิ่มเติม
สิ่งนี้ได้รับการชดเชยอย่างไร?
แม้ว่าพอยน์เตอร์จะถูกเก็บไว้อย่างชัดเจน (เช่นในโครงสร้างข้อมูลเช่นรายการ) โครงสร้างข้อมูลที่ได้มักจะมีความสง่างามกว่า (ง่ายกว่าง่ายต่อการเข้าใจง่ายต่อการจัดการ ฯลฯ ) กว่าโครงสร้างข้อมูลที่เทียบเท่าโดยไม่มีพอยน์เตอร์
พอยน์เตอร์ใช้ในเวลาที่แอปพลิเคชันหน่วยความจำเหลือน้อยหรือไม่?
ใช่. อุปกรณ์ที่ใช้ไมโครคอนโทรลเลอร์มักจะมีหน่วยความจำน้อยมาก แต่เฟิร์มแวร์อาจใช้พอยน์เตอร์สำหรับจัดการเวกเตอร์ขัดจังหวะหรือการจัดการบัฟเฟอร์ ฯลฯ
gcc -fverbose-asm -S -O2
รวบรวมคอมไพล์ C บางตัว)
การมีตัวชี้ใช้งานเหนือหัวอย่างแน่นอน แต่คุณสามารถเห็นส่วนต่างได้เช่นกันตัวชี้เป็นเหมือนดัชนี ใน C คุณสามารถใช้โครงสร้างข้อมูลที่ซับซ้อนเช่นสตริงและโครงสร้างเนื่องจากตัวชี้เท่านั้น
ในความเป็นจริงสมมติว่าคุณต้องการส่งผ่านตัวแปรโดยการอ้างอิงแล้วมันเป็นเรื่องง่ายที่จะรักษาตัวชี้แทนที่จะทำซ้ำโครงสร้างทั้งหมดและซิงโครไนซ์การเปลี่ยนแปลงระหว่างพวกเขา (แม้สำหรับการคัดลอกพวกเขา คุณจะจัดการกับการจัดสรรหน่วยความจำที่ไม่ต่อเนื่องและการจัดสรรโดยไม่ใช้ตัวชี้ได้อย่างไร
แม้แต่ตัวแปรปกติของคุณก็มีรายการในตารางสัญลักษณ์ที่เก็บที่อยู่ซึ่งตัวแปรของคุณชี้ไป ดังนั้นฉันไม่คิดว่ามันสร้างค่าใช้จ่ายมากในแง่ของหน่วยความจำ (เพียง 4 หรือ 8 ไบต์) แม้แต่ภาษาอย่าง java ใช้พอยน์เตอร์ภายใน (อ้างอิง) พวกเขาก็ไม่ยอมให้คุณจัดการกับมันเพราะมันจะทำให้ JVM ปลอดภัยน้อยกว่า
คุณควรใช้พอยน์เตอร์ก็ต่อเมื่อคุณไม่มีตัวเลือกอื่นเช่นประเภทข้อมูลที่ขาดหายไปโครงสร้าง (ใน c) เนื่องจากการใช้พอยน์เตอร์อาจทำให้เกิดข้อผิดพลาดได้หากไม่ได้รับการจัดการอย่างถูกต้องและยากต่อการดีบัก
ดังนั้นนี่ไม่ใช่ค่าใช้จ่ายหน่วยความจำ?
ใช่ .... ไม่ ... อาจจะ?
นี่เป็นคำถามที่น่าอึดอัดใจเพราะจินตนาการถึงช่วงที่อยู่หน่วยความจำบนเครื่องและซอฟต์แวร์ที่ต้องติดตามสิ่งที่อยู่ในหน่วยความจำอย่างต่อเนื่องซึ่งไม่สามารถผูกกับสแต็กได้
ตัวอย่างเช่นลองจินตนาการถึงเครื่องเล่นเพลงที่มีการโหลดไฟล์เพลงด้วยการกดปุ่มโดยผู้ใช้และยกเลิกการโหลดจากหน่วยความจำที่ระเหยได้เมื่อผู้ใช้พยายามโหลดไฟล์เพลงอื่น
เราจะติดตามตำแหน่งที่จัดเก็บข้อมูลเสียงได้อย่างไร เราต้องการที่อยู่หน่วยความจำ โปรแกรมไม่เพียง แต่ต้องติดตามข้อมูลเสียงในหน่วยความจำ แต่ยังอยู่ในหน่วยความจำ ดังนั้นเราต้องเก็บที่อยู่หน่วยความจำไว้ (เช่นตัวชี้) และขนาดของที่เก็บข้อมูลที่จำเป็นสำหรับที่อยู่หน่วยความจำจะตรงกับช่วงที่อยู่ของเครื่อง (เช่นตัวชี้ 64 บิตสำหรับช่วงที่อยู่ 64 บิต)
ดังนั้นมันจึงเป็น "ใช่" มันต้องการหน่วยเก็บข้อมูลในการติดตามที่อยู่หน่วยความจำ แต่ไม่ใช่ว่าเราสามารถหลีกเลี่ยงได้สำหรับหน่วยความจำที่จัดสรรแบบไดนามิกในประเภทนี้
สิ่งนี้ได้รับการชดเชยอย่างไร?
เมื่อพูดถึงขนาดของตัวชี้คุณสามารถหลีกเลี่ยงค่าใช้จ่ายในบางกรณีโดยการใช้สแต็คเช่นในกรณีนั้นคอมไพเลอร์สามารถสร้างคำสั่งที่มีประสิทธิภาพอย่างหนักรหัสที่อยู่หน่วยความจำแบบสัมพัทธ์หลีกเลี่ยงต้นทุนของตัวชี้ แต่สิ่งนี้ทำให้คุณมีความเสี่ยงที่จะสแต็คโอเวอร์โฟลว์หากคุณทำเช่นนี้สำหรับการจัดสรรขนาดใหญ่และขนาดตัวแปรและยังมีแนวโน้มที่จะทำไม่ได้ (หากไม่สามารถทำได้) ที่จะทำสำหรับซีรีส์สาขาที่ซับซ้อน ข้างบน).
อีกวิธีหนึ่งคือการใช้โครงสร้างข้อมูลที่ต่อเนื่องกันมากขึ้น ตัวอย่างเช่นลำดับตามอาร์เรย์อาจใช้แทนรายการที่ลิงก์สองเท่าซึ่งต้องใช้สองพอยน์เตอร์ต่อโหนด นอกจากนี้เรายังสามารถใช้ไฮบริดของทั้งสองนี้เป็นรายการที่ไม่ได้ควบคุมซึ่งจะเก็บเฉพาะพอยน์เตอร์ในระหว่างองค์ประกอบ N ที่ต่อเนื่องกันทุกกลุ่ม
พอยน์เตอร์ใช้ในเวลาที่แอปพลิเคชันหน่วยความจำเหลือน้อยหรือไม่?
ใช่โดยทั่วไปแล้วแอปพลิเคชั่นที่มีความสำคัญต่อประสิทธิภาพจะถูกเขียนใน C หรือ C ++ ซึ่งควบคุมโดยการใช้ตัวชี้ (อาจอยู่หลังตัวชี้สมาร์ทหรือคอนเทนเนอร์เช่นstd::vector
หรือstd::string
แต่กลไกพื้นฐานนั้นต้มลงไปถึงตัวชี้ที่ใช้ เพื่อติดตามที่อยู่ไปยังบล็อกหน่วยความจำแบบไดนามิก)
กลับไปที่คำถามนี้:
สิ่งนี้ได้รับการชดเชยอย่างไร? (ตอนที่สอง)
ตัวชี้มักจะสกปรกราคาถูกเว้นแต่ว่าคุณจัดเก็บเหมือนล้านคน (ซึ่งยังคงเป็น * 8 เมกะไบต์บนเครื่อง 64 บิต)
* โปรดสังเกตว่าเบ็นชี้ให้เห็นว่า "ความเลว" 8 เมกกะพิกเซลยังคงเป็นขนาดของแคช L3 ที่นี่ฉันใช้ "เลวร้ายยิ่ง" ในแง่ของการใช้ DRAM ทั้งหมดและขนาดสัมพัทธ์โดยทั่วไปของหน่วยความจำจะมีการใช้งานพอยน์เตอร์ที่มีสุขภาพดี
ในกรณีที่ตัวชี้ราคาแพงไม่ใช่ตัวชี้ แต่:
การจัดสรรหน่วยความจำแบบไดนามิก การจัดสรรหน่วยความจำแบบไดนามิกมีแนวโน้มที่จะมีค่าใช้จ่ายสูงเนื่องจากต้องผ่านโครงสร้างข้อมูลพื้นฐาน (เช่นตัวจัดสรรบัดดี้หรือแผ่นพื้น) แม้ว่าสิ่งเหล่านี้มักจะถูกปรับให้เหมาะกับความตาย แต่ก็มีจุดประสงค์ทั่วไปและออกแบบมาเพื่อจัดการบล็อกขนาดแปรปรวนที่ต้องการให้พวกเขาทำงานอย่างน้อยคล้ายกับ "ค้นหา" (แม้ว่าจะมีน้ำหนักเบาและอาจเป็นเวลาคงที่) ค้นหาชุดของหน้าต่อเนื่องฟรีในหน่วยความจำ
การเข้าถึงหน่วยความจำ นี่เป็นค่าใช้จ่ายที่ใหญ่กว่าที่จะต้องกังวล เมื่อใดก็ตามที่เราเข้าถึงหน่วยความจำที่จัดสรรแบบไดนามิกเป็นครั้งแรกมีข้อผิดพลาดในหน้าบังคับเช่นเดียวกับแคชคิดถึงการย้ายหน่วยความจำลงตามลำดับชั้นของหน่วยความจำและลงทะเบียน
การเข้าถึงหน่วยความจำ
การเข้าถึงหน่วยความจำเป็นหนึ่งในส่วนที่สำคัญที่สุดของประสิทธิภาพนอกเหนือจากอัลกอริทึม เขตข้อมูลที่มีประสิทธิภาพสูงเช่นเอนจิ้นเกม AAA มุ่งเน้นไปที่พลังงานที่มีต่อการปรับแต่งข้อมูลให้เหมาะสมซึ่งจะทำให้รูปแบบและการเข้าถึงหน่วยความจำมีประสิทธิภาพมากขึ้น
หนึ่งในปัญหาประสิทธิภาพที่ใหญ่ที่สุดของภาษาระดับสูงที่ต้องการจัดสรรแต่ละประเภทที่ผู้ใช้กำหนดแยกต่างหากผ่านตัวรวบรวมขยะเช่นพวกเขาสามารถแยกส่วนหน่วยความจำได้ค่อนข้างน้อย นี่อาจเป็นจริงโดยเฉพาะอย่างยิ่งหากไม่จัดสรรวัตถุทั้งหมดในคราวเดียว
ในกรณีดังกล่าวถ้าคุณเก็บรายการของวัตถุที่กำหนดโดยผู้ใช้หลายล้านรายการการเข้าถึงอินสแตนซ์เหล่านั้นเรียงตามลำดับในลูปอาจค่อนข้างช้าเนื่องจากคล้ายกับรายการล้านพอยน์เตอร์ ในกรณีดังกล่าวสถาปัตยกรรมต้องการดึงหน่วยความจำจากส่วนบน, ช้าลงและใหญ่ขึ้นของลำดับชั้นในกลุ่มก้อนขนาดใหญ่ที่เรียงกันด้วยความหวังว่าข้อมูลรอบข้างในกลุ่มเหล่านั้นจะถูกเข้าถึงก่อนที่จะถูกไล่ออก เมื่อแต่ละวัตถุในรายการดังกล่าวได้รับการจัดสรรแยกกันบ่อยครั้งเรามักจะจ่ายเงินให้กับมันด้วยแคชที่หายไปเมื่อแต่ละการทำซ้ำในภายหลังอาจต้องโหลดจากพื้นที่ที่แตกต่างกันอย่างสมบูรณ์ในหน่วยความจำโดยไม่มีวัตถุที่อยู่ติดกัน
คอมไพเลอร์จำนวนมากสำหรับภาษาดังกล่าวกำลังทำงานได้อย่างยอดเยี่ยมในทุกวันนี้ที่การเลือกคำสั่งและการจัดสรรการลงทะเบียน แต่การขาดการควบคุมโดยตรงมากกว่าการจัดการหน่วยความจำที่นี่สามารถเป็นนักฆ่า (แม้ว่ามักจะผิดพลาดน้อยกว่า) C และ C ++ ค่อนข้างเป็นที่นิยม
การเพิ่มประสิทธิภาพการเข้าถึงตัวชี้โดยทางอ้อม
ในสถานการณ์ที่มีประสิทธิภาพมากที่สุดแอปพลิเคชันมักจะใช้พูลหน่วยความจำซึ่งพูลหน่วยความจำจากกลุ่มที่ต่อเนื่องกันเพื่อปรับปรุงตำแหน่งอ้างอิง ในกรณีเช่นนี้แม้โครงสร้างที่เชื่อมโยงเช่นต้นไม้หรือรายการที่เชื่อมโยงสามารถทำแคชได้โดยง่ายหากรูปแบบหน่วยความจำของโหนดนั้นต่อเนื่องกันตามธรรมชาติ สิ่งนี้กำลังทำให้ตัวชี้การลดราคาถูกลงอย่างมีประสิทธิภาพแม้ว่าจะเป็นทางอ้อมโดยการปรับปรุงท้องถิ่นของการอ้างอิงที่เกี่ยวข้องเมื่อทำการยกเลิกการอ้างอิง
พอยน์เตอร์ไล่ตามสถานที่ต่างๆ
สมมติว่าเรามีรายการที่เชื่อมโยงเดี่ยว:
Foo->Bar->Baz->null
ปัญหาคือว่าถ้าเราจัดสรรโหนดเหล่านี้ทั้งหมดแยกจากกันกับตัวจัดสรรวัตถุประสงค์ทั่วไป (และอาจไม่ทั้งหมดในคราวเดียว) หน่วยความจำจริงอาจจะกระจายไปในลักษณะนี้ (แผนภาพง่าย):
เมื่อเราเริ่มไล่ตามพอยน์เตอร์และเข้าถึงFoo
โหนดเราเริ่มต้นด้วยการบังคับพลาด (และอาจเป็นความผิดพลาดของหน้า) การย้ายอันจากพื้นที่หน่วยความจำจากพื้นที่หน่วยความจำช้าลงไปสู่พื้นที่หน่วยความจำที่เร็วขึ้นเช่น:
สิ่งนี้ทำให้เราแคช (อาจเป็นหน้า) พื้นที่หน่วยความจำเท่านั้นเพื่อเข้าถึงส่วนหนึ่งของมันและขับไล่ส่วนที่เหลือเมื่อเราไล่ล่าพอยน์เตอร์รอบรายการนี้ อย่างไรก็ตามโดยการควบคุมตัวจัดสรรหน่วยความจำอย่างไรก็ตามเราสามารถจัดสรรรายการดังกล่าวได้อย่างต่อเนื่องเช่น:
... และด้วยเหตุนี้จึงปรับปรุงความเร็วที่เราสามารถตรวจสอบพอยน์เตอร์และประมวลผลคะแนนของพวกเขาได้อย่างมีนัยสำคัญ ดังนั้นแม้ว่าจะเป็นทางอ้อมมากเราสามารถเร่งความเร็วการเข้าถึงตัวชี้ได้ด้วยวิธีนี้ แน่นอนถ้าเราเพิ่งเก็บสิ่งเหล่านี้อย่างต่อเนื่องในอาเรย์เราจะไม่พบปัญหานี้ในตอนแรก แต่ตัวจัดสรรหน่วยความจำที่นี่ทำให้เราสามารถควบคุมเลย์เอาต์ของหน่วยความจำอย่างชัดเจนสามารถบันทึกวันเมื่อต้องการโครงสร้างที่เชื่อมโยง
* หมายเหตุ: นี่เป็นไดอะแกรมที่มีความซับซ้อนมากและการอภิปรายเกี่ยวกับลำดับชั้นหน่วยความจำและสถานที่อ้างอิง แต่หวังว่ามันจะเหมาะสมสำหรับระดับของคำถาม
ดังนั้นนี่ไม่ใช่ค่าใช้จ่ายหน่วยความจำ?
มันเป็นค่าใช้จ่ายในความทรงจำจริง ๆ แต่มีขนาดเล็กมาก (จนถึงจุดที่ไม่มีนัยสำคัญ)
สิ่งนี้ได้รับการชดเชยอย่างไร?
มันไม่ได้รับการชดเชย คุณจำเป็นต้องตระหนักว่าการเข้าถึงข้อมูลผ่านตัวชี้ (การยกเลิกการลงทะเบียนตัวชี้) นั้นเร็วมาก (ถ้าฉันจำได้อย่างถูกต้อง มันเร็วพอที่จะเป็นทางเลือกที่เร็วที่สุดที่คุณมีในหลาย ๆ กรณี
พอยน์เตอร์ใช้ในเวลาที่แอปพลิเคชันหน่วยความจำเหลือน้อยหรือไม่?
ใช่.
คุณต้องการการใช้หน่วยความจำเพิ่มเติมเท่านั้น (โดยทั่วไปแล้ว 4-8 ไบต์ต่อตัวชี้) ในขณะที่คุณต้องการตัวชี้นั้น มีเทคนิคมากมายที่ทำให้ราคาไม่แพงมาก
เทคนิคพื้นฐานที่สุดที่ทำให้พอยน์เตอร์ทรงพลังคือคุณไม่จำเป็นต้องเก็บตัวชี้ทุกตัว บางครั้งคุณสามารถใช้อัลกอริทึมเพื่อสร้างตัวชี้จากตัวชี้ไปยังอย่างอื่น ตัวอย่างเล็กน้อยที่สุดของเรื่องนี้คือการคำนวณทางคณิตศาสตร์ หากคุณจัดสรรอาร์เรย์จำนวนเต็ม 50 ตัวคุณไม่จำเป็นต้องเก็บ 50 พอยน์เตอร์ไว้หนึ่งตัวต่อจำนวนเต็ม โดยทั่วไปแล้วคุณจะติดตามตัวชี้หนึ่งตัว (ตัวแรก) และใช้ตัวคำนวณเลขคณิตเพื่อสร้างตัวชี้อื่น ๆ ได้ทันที บางครั้งคุณอาจเก็บพอยน์เตอร์เหล่านั้นไว้ในองค์ประกอบเฉพาะของอาร์เรย์ชั่วคราว แต่เฉพาะเมื่อคุณต้องการ เมื่อเสร็จแล้วคุณสามารถยกเลิกได้ตราบใดที่คุณมีข้อมูลเพียงพอที่จะสร้างใหม่ในภายหลังหากคุณต้องการ สิ่งนี้อาจฟังดูเล็กน้อย แต่เป็นเครื่องมือการอนุรักษ์ที่คุณต้องการ
ในสถานการณ์ที่มีหน่วยความจำน้อยมากสิ่งนี้สามารถใช้เพื่อลดค่าใช้จ่าย หากคุณกำลังทำงานในพื้นที่หน่วยความจำที่แคบมากคุณมักจะมีความรู้สึกถึงจำนวนวัตถุที่คุณต้องจัดการ แทนที่จะจัดสรรจำนวนเต็มทีละหนึ่งครั้งและเก็บพอยน์เตอร์แบบเต็มคุณสามารถใช้ประโยชน์จากความรู้ของนักพัฒนาของคุณว่าคุณจะไม่มีจำนวนเต็มมากกว่า 256 ตัวในอัลกอริทึมนี้โดยเฉพาะ ในกรณีดังกล่าวคุณอาจเก็บตัวชี้ไปที่จำนวนเต็มแรกและติดตามดัชนีโดยใช้อักขระถ่าน (1 ไบต์) แทนที่จะใช้ตัวชี้แบบเต็ม (4/8 ไบต์) คุณอาจใช้เทคนิคอัลกอริทึมเพื่อสร้างดัชนีเหล่านี้ได้ทันที
หน่วยความจำประเภทนี้เป็นที่นิยมอย่างมากในอดีต ตัวอย่างเช่นเกม NES จะพึ่งพาความสามารถในการอัดข้อมูลและสร้างพอยน์เตอร์อัลกอริธึมอย่างกว้างขวาง
สถานการณ์หน่วยความจำขั้นสูงยังสามารถนำไปสู่การทำสิ่งต่างๆเช่นการจัดสรรพื้นที่ทั้งหมดที่คุณทำงานในเวลารวบรวม จากนั้นตัวชี้ที่คุณต้องเก็บไว้ในหน่วยความจำนั้นจะถูกเก็บไว้ในโปรแกรมแทนที่จะเป็นข้อมูล ในสถานการณ์ที่มีข้อ จำกัด ด้านหน่วยความจำคุณมีโปรแกรมและหน่วยความจำข้อมูลแยกต่างหาก (มักเป็น ROM กับ RAM) ดังนั้นคุณอาจปรับวิธีที่คุณใช้อัลกอริทึมของคุณเพื่อดันพอยน์เตอร์ไปยังหน่วยความจำของโปรแกรมนั้น
โดยพื้นฐานแล้วคุณไม่สามารถกำจัดค่าใช้จ่ายทั้งหมดได้ อย่างไรก็ตามคุณสามารถควบคุมมันได้ โดยใช้เทคนิคอัลกอริทึมคุณสามารถลดจำนวนพอยน์เตอร์ที่คุณสามารถจัดเก็บได้ หากคุณกำลังใช้พอยน์เตอร์กับหน่วยความจำแบบไดนามิกคุณจะไม่ได้รับค่าใช้จ่ายในการรักษาตัวชี้ 1 ไปยังจุดหน่วยความจำแบบไดนามิกนั้นเพราะนั่นเป็นข้อมูลขั้นต่ำที่จำเป็นในการเข้าถึงทุกอย่างในบล็อกหน่วยความจำนั้น อย่างไรก็ตามในสถานการณ์ข้อ จำกัด ของหน่วยความจำ ultra-tight นี่เป็นกรณีพิเศษ (หน่วยความจำแบบไดนามิกและข้อ จำกัด ของหน่วยความจำแบบ ultra-tight มักจะไม่ปรากฏในสถานการณ์เดียวกัน)
ในหลาย ๆ สถานการณ์พอยน์เตอร์จะบันทึกหน่วยความจำจริง ทางเลือกทั่วไปในการใช้พอยน์เตอร์คือการทำสำเนาโครงสร้างข้อมูล สำเนาของโครงสร้างข้อมูลจะมีขนาดใหญ่กว่าตัวชี้
ตัวอย่างหนึ่งของแอปพลิเคชั่นที่สำคัญเวลาคือสแต็กเครือข่าย สแต็กเครือข่ายที่ดีจะได้รับการออกแบบให้เป็น "zero copy" - และการทำเช่นนี้ต้องใช้พอยน์เตอร์ที่ฉลาด