ตัวอย่างที่น่าสนใจของตัวจัดสรร C ++ แบบกำหนดเอง


176

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

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

คำตอบ:


121

ดังที่ฉันพูดถึงที่นี่ฉันเห็นตัวปันส่วน STL ที่กำหนดเองของ Intel TBB ปรับปรุงประสิทธิภาพของแอพแบบมัลติเธรดอย่างมากเพียงแค่เปลี่ยนแอปเดียว

std::vector<T>

ถึง

std::vector<T,tbb::scalable_allocator<T> >

(นี่เป็นวิธีที่สะดวกและรวดเร็วในการสลับตัวจัดสรรเพื่อใช้ฮีปเธรดส่วนตัวที่ดีของ TBB ดูหน้า 7 ในเอกสารนี้ )


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

7
ลิงก์เดิมหมดอายุแล้ว แต่ CiteSeer มี PDF: citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.71.8289
Arto Bendiken

1
ฉันต้องถามว่า: คุณสามารถย้ายเวกเตอร์ดังกล่าวไปยังหัวข้ออื่นได้หรือไม่? (ฉันคาดเดาไม่ได้)
sellibitze

@sellibitze: เนื่องจากเวกเตอร์ได้รับการจัดการจากภายในงาน TBB และนำกลับมาใช้ใหม่ในการดำเนินงานแบบขนานหลายครั้งและไม่มีการรับประกันใดที่เธรดของผู้ปฏิบัติงาน TBB จะรับงานฉันจึงสรุปว่ามันใช้ได้ดี แม้ว่าทราบว่ามีปัญหาในอดีตบางอย่างเกี่ยวกับการปล่อยสิ่งที่ TBB สร้างขึ้นในหนึ่งเธรดในเธรดอื่น (เห็นได้ชัดว่าเป็นปัญหาแบบคลาสสิกกับ heap ส่วนตัวของเธรดและรูปแบบการจัดสรร & การจัดสรรคืน . คงบางทีในรุ่นที่ใหม่กว่า).
timday

@ArtoBendiken: ลิงค์ดาวน์โหลดที่ลิงค์ของคุณดูเหมือนจะไม่ถูกต้อง
einpoklum

81

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

EASTL - ห้องสมุดเทมเพลตมาตรฐานศิลปะอิเล็กทรอนิกส์


14
+1 สำหรับลิงก์ EASTL: "ในบรรดาผู้พัฒนาเกมจุดอ่อนพื้นฐานที่สำคัญที่สุด [ของ STL] คือการออกแบบตัวจัดสรร std และเป็นจุดอ่อนนี้ซึ่งเป็นปัจจัยที่มีส่วนสำคัญที่สุดในการสร้าง EASTL"
Naaff

65

ฉันกำลังทำงานกับตัวจัดสรร mmap ที่อนุญาตให้เวกเตอร์ใช้หน่วยความจำจากไฟล์ที่แม็พหน่วยความจำ เป้าหมายคือเพื่อให้มีเวกเตอร์ที่ใช้หน่วยเก็บข้อมูลที่อยู่ในหน่วยความจำเสมือนที่แมปโดย mmap โดยตรง ปัญหาของเราคือการปรับปรุงการอ่านไฟล์ที่มีขนาดใหญ่มาก (> 10GB) ในหน่วยความจำโดยไม่มีการคัดลอกดังนั้นฉันต้องใช้ตัวจัดสรรที่กำหนดเองนี้

จนถึงตอนนี้ฉันมีโครงกระดูกของตัวจัดสรรที่กำหนดเอง (ซึ่งมาจาก std :: allocator) ฉันคิดว่ามันเป็นจุดเริ่มต้นที่ดีในการเขียนตัวจัดสรรของตัวเอง อย่าลังเลที่จะใช้โค้ดชิ้นนี้ในแบบที่คุณต้องการ:

#include <memory>
#include <stdio.h>

namespace mmap_allocator_namespace
{
        // See StackOverflow replies to this answer for important commentary about inheriting from std::allocator before replicating this code.
        template <typename T>
        class mmap_allocator: public std::allocator<T>
        {
public:
                typedef size_t size_type;
                typedef T* pointer;
                typedef const T* const_pointer;

                template<typename _Tp1>
                struct rebind
                {
                        typedef mmap_allocator<_Tp1> other;
                };

                pointer allocate(size_type n, const void *hint=0)
                {
                        fprintf(stderr, "Alloc %d bytes.\n", n*sizeof(T));
                        return std::allocator<T>::allocate(n, hint);
                }

                void deallocate(pointer p, size_type n)
                {
                        fprintf(stderr, "Dealloc %d bytes (%p).\n", n*sizeof(T), p);
                        return std::allocator<T>::deallocate(p, n);
                }

                mmap_allocator() throw(): std::allocator<T>() { fprintf(stderr, "Hello allocator!\n"); }
                mmap_allocator(const mmap_allocator &a) throw(): std::allocator<T>(a) { }
                template <class U>                    
                mmap_allocator(const mmap_allocator<U> &a) throw(): std::allocator<T>(a) { }
                ~mmap_allocator() throw() { }
        };
}

หากต้องการใช้สิ่งนี้ให้ประกาศคอนเทนเนอร์ STL ดังนี้:

using namespace std;
using namespace mmap_allocator_namespace;

vector<int, mmap_allocator<int> > int_vec(1024, 0, mmap_allocator<int>());

มันสามารถใช้สำหรับการเข้าสู่ระบบทุกครั้งที่มีการจัดสรรหน่วยความจำ สิ่งที่จำเป็นคือโครงสร้างการเชื่อมโยงมิฉะนั้นคอนเทนเนอร์เวกเตอร์จะใช้ superclasses จัดสรรวิธี / deallocate

อัปเดต: ตัวจัดสรรการแมปหน่วยความจำมีให้บริการแล้วที่https://github.com/johannesthoma/mmap_allocatorและเป็น LGPL อย่าลังเลที่จะใช้มันสำหรับโครงการของคุณ


17
แค่หัวขึ้นมาจาก std :: allocator ไม่ใช่วิธีการเขียนตัวจัดสรร คุณควรดู allocator_traits แทนซึ่งช่วยให้คุณสามารถจัดหาฟังก์ชันการทำงานขั้นต่ำเปล่าได้และคลาสลักษณะจะให้ส่วนที่เหลือ โปรดทราบว่า STL จะใช้ตัวจัดสรรของคุณผ่าน allocator_traits เสมอไม่ใช่โดยตรงดังนั้นคุณไม่จำเป็นต้องอ้างถึง allocator_traits ด้วยตัวคุณเองไม่มีแรงจูงใจมากนักที่จะได้รับจาก std :: allocator (แม้ว่ารหัสนี้อาจเป็นจุดเริ่มต้นที่เป็นประโยชน์ก็ตาม)
Nir Friedman

25

ฉันทำงานกับเครื่องมือจัดเก็บข้อมูล MySQL ที่ใช้ c ++ สำหรับรหัสของมัน เรากำลังใช้ตัวจัดสรรที่กำหนดเองเพื่อใช้ระบบหน่วยความจำ MySQL แทนที่จะแข่งขันกับ MySQL สำหรับหน่วยความจำ มันช่วยให้เราแน่ใจได้ว่าเราใช้หน่วยความจำในขณะที่ผู้ใช้กำหนดค่า MySQL ให้ใช้ไม่ใช่ "พิเศษ"


21

มันจะมีประโยชน์ในการใช้ตัวจัดสรรที่กำหนดเองเพื่อใช้พูลหน่วยความจำแทนฮีป นั่นเป็นตัวอย่างหนึ่งของคนอื่น ๆ

สำหรับกรณีส่วนใหญ่นี่เป็นการเพิ่มประสิทธิภาพก่อนเวลาอันแน่นอน แต่มันจะมีประโยชน์มากในบริบทบางอย่าง (อุปกรณ์ฝังตัวเกม ฯลฯ )


3
หรือเมื่อมีการแชร์พูลหน่วยความจำนั้น
แอนโทนี่

9

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

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


5
ดูเหมือนว่าตัวอย่างแรกคืองานของผู้ทำลายล้างไม่ใช่ผู้จัดสรร
Michael Dorst

2
หากคุณกังวลเกี่ยวกับโปรแกรมของคุณขึ้นอยู่กับเนื้อหาเริ่มต้นของหน่วยความจำจากฮีปการรันใน valgrind แบบรวดเร็ว (เช่นข้ามคืน!) จะแจ้งให้คุณทราบทางใดทางหนึ่ง
cdyson37

3
@ anthomomorphic: destructor และตัวจัดสรรแบบกำหนดเองจะทำงานร่วมกัน destructor จะทำงานก่อนจากนั้นจึงลบตัวจัดสรรแบบกำหนดเองซึ่งจะไม่เรียกฟรี (... ) แต่จะเรียกว่าว่าง (... ) ในภายหลังเมื่อให้บริการคำขอเสร็จสิ้น นี่อาจเร็วกว่าตัวจัดสรรเริ่มต้นและลดการกระจายตัวของพื้นที่ที่อยู่
คะแนน

8

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

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

  1. ผ่านการจัดสรรที่กำหนดเองจะมีการแจ้งเตือนตัวเร่งความเร็วหรือไดรเวอร์ของบล็อกหน่วยความจำ
  2. นอกจากนี้ระบบปฏิบัติการสามารถตรวจสอบให้แน่ใจว่าบล็อกของหน่วยความจำที่จัดสรรไว้เป็นหน้าล็อค (บางคนเรียกหน่วยความจำที่ปักหมุด ) นั่นคือระบบย่อยหน่วยความจำเสมือนของระบบปฏิบัติการอาจไม่ย้ายหรือลบหน้าภายในหรือออกจากหน่วยความจำ
  3. ถ้า 1 และ 2. ถือและการถ่ายโอนข้อมูลระหว่างบล็อกหน่วยความจำที่ล็อคหน้าและเร่งความเร็วรันไทม์สามารถเข้าถึงข้อมูลโดยตรงในหน่วยความจำหลักเนื่องจากมันรู้ว่ามันอยู่ที่ไหนและสามารถมั่นใจได้ว่าระบบปฏิบัติการไม่ได้ ย้าย / นำออก
  4. สิ่งนี้จะบันทึกสำเนาหน่วยความจำหนึ่งชุดที่จะเกิดขึ้นกับหน่วยความจำที่จัดสรรในแบบที่ไม่ได้ล็อคหน้า: ข้อมูลจะต้องคัดลอกในหน่วยความจำหลักไปยังพื้นที่จัดเก็บหน้าที่ถูกล็อคหน้าด้วยคันเร่ง )

1
... ที่จะไม่ลืมบล็อกหน่วยความจำชิดหน้า สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณกำลังพูดคุยกับคนขับ (เช่นกับ FPGAs ผ่าน DMA) และไม่ต้องการความยุ่งยากและค่าใช้จ่ายในการคำนวณค่าชดเชยในหน้าสำหรับนักกระจาย DMA ของคุณ
Jan

7

ฉันใช้ตัวจัดสรรแบบกำหนดเองที่นี่ คุณก็อาจจะบอกว่ามันคือการทำงานรอบจัดการหน่วยความจำแบบไดนามิกกำหนดเองอื่น ๆ

ความเป็นมา: เรามี overloads สำหรับ malloc, calloc, ฟรีและตัวแปรต่างๆของโอเปอเรเตอร์ใหม่และลบและ linker ทำให้ STL ใช้สิ่งเหล่านี้อย่างมีความสุขสำหรับเรา สิ่งนี้ช่วยให้เราสามารถทำสิ่งต่าง ๆ เช่นการรวมวัตถุขนาดเล็กอัตโนมัติการตรวจจับการรั่วไหลการเติมการเติมการเติมฟรีการจัดสรรช่องว่างด้วย Sentries การจัดแนวแคชของ allocs และล่าช้าฟรี

ปัญหาคือเรากำลังทำงานในสภาพแวดล้อมแบบฝังตัว - มีหน่วยความจำไม่เพียงพอที่จะทำการตรวจจับการรั่วของบัญชีอย่างถูกต้องในช่วงระยะเวลานาน อย่างน้อยไม่ได้อยู่ใน RAM มาตรฐาน - มี RAM อีกจำนวนหนึ่งให้ใช้ที่อื่นผ่านฟังก์ชั่นการจัดสรรแบบกำหนดเอง

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

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


5

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


4

สถานการณ์ที่สำคัญอย่างหนึ่ง: เมื่อเขียนโค้ดที่ต้องทำงานข้ามขอบเขตของโมดูล (EXE / DLL) มันเป็นสิ่งสำคัญที่จะทำให้การจัดสรรและการลบเกิดขึ้นในโมดูลเดียวเท่านั้น

ที่ฉันเจอนี่คือสถาปัตยกรรมปลั๊กอินบน Windows มันเป็นสิ่งสำคัญที่ตัวอย่างเช่นถ้าคุณส่งผ่าน std :: string ข้ามขอบเขต DLL การจัดสรรใหม่ของสตริงเกิดขึ้นจากฮีปที่มาจากฮีปนั้นไม่ใช่ฮีปใน DLL ซึ่งอาจแตกต่างกัน *

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


ถ้าคุณส่งวัตถุข้ามขอบเขต DLL คุณควรใช้การตั้งค่า DLL แบบหลายเธรด (Debug) (MD) (d) สำหรับทั้งสองฝ่าย C ++ ไม่ได้รับการออกแบบโดยคำนึงถึงการสนับสนุนโมดูล อีกวิธีหนึ่งคือคุณสามารถป้องกันทุกอย่างที่อยู่เบื้องหลังส่วนต่อประสาน COM และใช้ CoTaskMemAlloc นี่เป็นวิธีที่ดีที่สุดในการใช้อินเทอร์เฟซปลั๊กอินซึ่งไม่ได้ผูกไว้กับคอมไพเลอร์ STL หรือผู้จำหน่ายเฉพาะ
gast128

กฎของคนแก่คือ: อย่าทำอย่างนั้น อย่าใช้ประเภท STL ใน DLL API และอย่าผ่านหน่วยความจำแบบไดนามิกโดยไม่ต้องรับผิดชอบข้ามขอบเขต DLL API ไม่มี C ++ ABI - ดังนั้นหากคุณใช้ DLL ทุกตัวเป็น C API คุณจะหลีกเลี่ยงปัญหาที่อาจเกิดขึ้นได้ ด้วยค่าใช้จ่ายของ "c ++ beauty" แน่นอน หรือเป็นความคิดเห็นอื่น ๆ ที่แนะนำ: ใช้ COM แค่ธรรมดา C ++ เป็นความคิดที่ไม่ดี
BitTickler

3

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

โครงการหนึ่งที่ฉันกำลังทำอยู่คือใช้ AVR-GCC กับชิปที่มีกำลังไฟต่ำ เราต้องเก็บ 8 ความยาวของตัวแปร แต่มีค่าสูงสุดที่ทราบ การใช้งานไลบรารีมาตรฐานของการจัดการหน่วยความจำเป็น wrapper เล็ก ๆ รอบ malloc / free ซึ่งติดตามตำแหน่งที่จะวางไอเท็มด้วยการเตรียมทุกบล็อกของหน่วยความจำที่จัดสรรไว้ด้วยตัวชี้เพื่อผ่านจุดสิ้นสุดของหน่วยความจำที่จัดสรรไว้นั้น เมื่อทำการจัดสรรหน่วยความจำชิ้นใหม่ผู้จัดสรรมาตรฐานจะต้องเดินผ่านแต่ละส่วนของหน่วยความจำเพื่อค้นหาบล็อกถัดไปที่มีให้ซึ่งขนาดของหน่วยความจำที่ร้องขอจะพอดี บนแพลตฟอร์มเดสก์ท็อปสิ่งนี้จะเร็วมากสำหรับไอเท็มสองสามตัวนี้ แต่คุณต้องจำไว้ว่าไมโครคอนโทรลเลอร์เหล่านี้บางตัวนั้นช้ามากและเป็นแบบดั้งเดิม นอกจากนี้ปัญหาการกระจายตัวของหน่วยความจำเป็นปัญหาใหญ่ที่หมายความว่าเราไม่มีทางเลือกจริง ๆ แต่ต้องใช้แนวทางที่แตกต่าง

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

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


3

หน้าที่เชื่อมโยงกับ CppCon 2015 ของ Andrei Alexandrescu พูดคุยกับผู้จัดสรร:

https://www.youtube.com/watch?v=LIb3L4vKZ7U

สิ่งที่ดีคือการคิดพวกเขาทำให้คุณนึกถึงความคิดว่าคุณจะใช้มันอย่างไร :-)


2

สำหรับหน่วยความจำที่ใช้ร่วมกันเป็นสิ่งสำคัญที่ไม่เพียง แต่ส่วนหัวของคอนเทนเนอร์ แต่ยังมีข้อมูลที่เก็บไว้ในหน่วยความจำที่ใช้ร่วมกัน

ตัวจัดสรรของBoost :: Interprocessเป็นตัวอย่างที่ดี อย่างไรก็ตามในขณะที่คุณสามารถอ่านได้ที่นี่ allone นี้ไม่พอเพียงเพื่อให้คอนเทนเนอร์ STL ทั้งหมดใช้หน่วยความจำที่ใช้ร่วมกันได้ (เนื่องจากการแมปที่แตกต่างกันในกระบวนการที่แตกต่างกันตัวชี้อาจ "หยุด")


2

บางครั้งที่ผ่านมาผมพบว่าวิธีนี้มีประโยชน์มากกับฉัน: C ++ ด่วน 11 จัดสรรสำหรับบรรจุ มันเพิ่มความเร็วในคอนเทนเนอร์ STL เล็กน้อยใน VS2017 (~ 5x) เช่นเดียวกับ GCC (~ 7x) มันเป็นตัวจัดสรรวัตถุประสงค์พิเศษตามพูลหน่วยความจำ มันสามารถใช้กับคอนเทนเนอร์ STL ได้ด้วยกลไกที่คุณขอเท่านั้น


1

ฉันใช้ Loki :: Allocator / SmallObject เป็นการส่วนตัวเพื่อเพิ่มประสิทธิภาพการใช้หน่วยความจำสำหรับวัตถุขนาดเล็ก - มันแสดงประสิทธิภาพที่ดีและประสิทธิภาพการทำงานที่น่าพอใจถ้าคุณต้องทำงานกับวัตถุขนาดเล็กจำนวนปานกลาง (1 ถึง 256 ไบต์) มันอาจมีประสิทธิภาพมากกว่า ~ 30 เท่าของการจัดสรรใหม่ / ลบมาตรฐาน C ++ ถ้าเราพูดถึงการจัดสรรวัตถุขนาดเล็กที่มีขนาดแตกต่างกันจำนวนปานกลาง นอกจากนี้ยังมีโซลูชันเฉพาะ VC ที่เรียกว่า "QuickHeap" ซึ่งให้ประสิทธิภาพที่ดีที่สุด (จัดสรรและยกเลิกการจัดสรรเพียงแค่อ่านและเขียนที่อยู่ของบล็อกที่ถูกจัดสรร / ส่งคืนไปยังฮีปตามลำดับสูงสุด 99 รายการ (9)% - ขึ้นอยู่กับการตั้งค่าและการกำหนดค่าเริ่มต้น) แต่ด้วยค่าใช้จ่ายที่น่าทึ่ง - ต้องใช้ตัวชี้สองตัวต่อขอบเขตและอีกหนึ่งตัวสำหรับบล็อกหน่วยความจำใหม่แต่ละบล็อก มัน'

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


1

ในการจำลองกราฟิกฉันเคยเห็นตัวจัดสรรที่กำหนดเองมาใช้

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