ตัวจัดสรรฮีปแบบกำหนดเอง


9

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

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

การเขียนโปรแกรมเกม (อย่างน้อยกับเกมที่มีความทะเยอทะยานเกี่ยวกับการผลักฮาร์ดแวร์) บางครั้งก็อยู่ระหว่าง: คุณสามารถใช้การจัดสรรแบบไดนามิก แต่มีหน่วยความจำเพียงพอและมีข้อ จำกัด แบบเรียลไทม์อ่อนที่คุณไม่สามารถถือว่าตัวจัดสรรเป็นกล่องดำ ให้ใช้การรวบรวมขยะอย่างเดียวดังนั้นคุณต้องใช้ตัวจัดสรรแบบกำหนดเอง นี่คือหนึ่งในเหตุผลที่ C ++ ยังคงใช้กันอย่างแพร่หลายในอุตสาหกรรมเกม มันช่วยให้คุณทำสิ่งต่าง ๆ เช่นhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html

มีโดเมนอื่นใดบ้างที่อยู่ระหว่างนั้น? นอกเหนือจากเกมแล้วมีการใช้ตัวจัดสรรแบบกำหนดเองอย่างหนักที่ไหน?


1
บาง OSes ใช้slab allocatorซึ่งให้การแคชวัตถุ แต่ยังสามารถใช้เพื่อลดความขัดแย้งของตัวประมวลผลแคชโดยการแมปสมาชิกของวัตถุไปยังชุดที่แตกต่างกันสำหรับ modulo 2 ** N ทำดัชนีแคช (ทั้งสองโดยมีหลายอินสแตนซ์ในหน่วยความจำต่อเนื่องและ โดยการเติมตัวแปรภายในพื้น) พฤติกรรมแคชอาจมีความสำคัญมากกว่าการจัดสรร / ความเร็วอิสระหรือการใช้หน่วยความจำในบางกรณี
Paul A. Clayton

คำตอบ:


4

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

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

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

ในงานปัจจุบันของฉันฉันทำงานกับกล้องบันทึกวิดีโอดิจิตอลและแพ็คเกจการวิเคราะห์ ที่ 30 fps แต่ละช่องจะได้รับเฟรมวิดีโอทุก 33 มิลลิวินาที บนฮาร์ดแวร์ที่เราขายเราสามารถบันทึกวิดีโอได้ 100 ช่อง ดังนั้นจึงเป็นอีกกรณีหนึ่งที่ต้องตรวจสอบให้แน่ใจว่าในเส้นทางที่สำคัญ (การเรียกเครือข่าย => การจับส่วนประกอบ => ซอฟต์แวร์การจัดการเครื่องบันทึก => ส่วนประกอบการจัดเก็บ => ดิสก์) ไม่มีการจัดสรรหน่วยความจำแบบไดนามิก เรามีตัวจัดสรรเฟรมแบบกำหนดเองซึ่งมีที่เก็บขนาดคงที่ของบัฟเฟอร์และใช้ LIFO เพื่อนำบัฟเฟอร์ที่จัดสรรก่อนหน้านี้มาใช้ใหม่ หากคุณต้องการพื้นที่เก็บข้อมูล 600Kb คุณอาจท้ายด้วยบัฟเฟอร์ 1024Kb ซึ่งเปลืองพื้นที่ แต่เนื่องจากมันได้รับการปรับแต่งเป็นพิเศษสำหรับการใช้งานของเราโดยที่การจัดสรรแต่ละครั้งนั้นสั้นมากจึงทำได้ดีมากเพราะใช้บัฟเฟอร์

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


"เราได้ใช้ความพยายามอย่างเต็มที่เพื่อให้แน่ใจว่า malloc / free ไม่ได้ถูกเรียกเว้นแต่ว่าพวกเขาจำเป็นจริงๆ ... " - ฉันรู้ว่ามีฮาร์ดแวร์บางตัวที่สร้างเราเตอร์ malloc/freeพวกเขาไม่ได้รำคาญกับ พวกเขาจองบล็อกของหน่วยความจำและใช้เป็นโครงสร้างข้อมูลเคอร์เซอร์ งานส่วนใหญ่ของพวกเขาลดลงเพื่อติดตามดัชนี

4

การประมวลผลวิดีโอ, VFX, ระบบปฏิบัติการ ฯลฯ มักจะมีคนใช้มากเกินไป ไม่จำเป็นต้องแยกโครงสร้างข้อมูลและตัวจัดสรรเพื่อให้การจัดสรรมีประสิทธิภาพ

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

ใน C ++ ตัวอย่างเช่นหนึ่งในผลข้างเคียงที่ชะลอของการมีคอนเทนเนอร์มาตรฐานพึ่งพาตัวจัดสรรภายนอกได้สร้างโครงสร้างที่เชื่อมโยงเช่นstd::mapและstd::listถือว่าไร้ประโยชน์โดยชุมชน C ++ เนื่องจากพวกเขากำลังเปรียบเทียบกับstd::allocatorในขณะที่โครงสร้างข้อมูลเหล่านี้จัดสรรทีละหนึ่งโหนด แน่นอนว่าโครงสร้างการเชื่อมโยงของคุณจะทำงานได้ไม่ดีในกรณีนั้น แต่สิ่งต่าง ๆ จะกลับกลายเป็นอย่างมากหากการจัดสรรโหนดที่มีประสิทธิภาพสำหรับโครงสร้างที่เชื่อมโยงนั้นถือเป็นความรับผิดชอบของโครงสร้างข้อมูลแทนที่จะเป็นตัวจัดสรร พวกเขายังคงใช้การจัดสรรแบบกำหนดเองด้วยเหตุผลอื่นเช่นการติดตามหน่วยความจำ / การทำโปรไฟล์ แต่ต้องพึ่งพาตัวจัดสรรเพื่อทำให้โครงสร้างที่เชื่อมโยงมีประสิทธิภาพในขณะที่พยายามจัดสรรโหนดครั้งละครั้งทำให้พวกเขาทั้งหมดโดยค่าเริ่มต้นไม่มีประสิทธิภาพมาก ซึ่งจะไม่เป็นไรถ้ามาพร้อมกับ caveat ที่รู้จักกันดีว่าโครงสร้างที่เชื่อมโยงในตอนนี้ต้องการตัวจัดสรรแบบกำหนดเองเช่นรายการฟรีเพื่อให้มีประสิทธิภาพพอสมควรและหลีกเลี่ยงการเรียกแคชที่พลาดไปทางซ้ายและขวา การใช้งานได้จริงมากขึ้นอาจเป็นสิ่งที่ต้องการstd::list<T, BlockSize, Alloc>โดยที่BlockSizeระบุจำนวนโหนดที่ต่อเนื่องกันที่จะจัดสรรพร้อมกันสำหรับรายการฟรี (การระบุ 1 จะนำไปสู่ประสิทธิภาพอย่างที่std::listเป็นอยู่ในขณะนี้)

แต่ไม่มีข้อแม้เช่นนั้นซึ่งนำไปสู่ชุมชนทั้งหมดของ blockheads ที่สะท้อนให้เห็นถึงลัทธิมนต์ที่รายการที่เชื่อมโยงนั้นไร้ประโยชน์เช่น


3

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

นอกเหนือจากเกมแล้วมีการใช้ตัวจัดสรรแบบกำหนดเองอย่างหนักที่ไหน?

Facebook

ลองดูjemallocที่ Facebook เริ่มใช้เพื่อปรับปรุงประสิทธิภาพของฮีปและลดการกระจายตัว


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