มีการจำกัดความยาวสูงสุดของอาร์เรย์ใน C ++ หรือไม่


183

มีความยาวสูงสุดสำหรับอาร์เรย์ใน C ++ หรือไม่

มันเป็นขีด จำกัด ของ C ++ หรือขึ้นอยู่กับเครื่องของฉันด้วย? มันปรับเปลี่ยนได้หรือไม่? มันขึ้นอยู่กับชนิดของอาร์เรย์ที่ทำหรือไม่?

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

สิ่งที่ฉันต้องทำก็คือการเก็บ int ไว้ในอาร์เรย์มานานฉันทำงานในระบบ Linux คำถามของฉันคือฉันต้องทำอย่างไรถ้าฉันต้องการเก็บอาเรย์ของจำนวนเต็มความยาว N ที่มี N> 10 หลัก

ฉันต้องการสิ่งนี้เพราะฉันกำลังเขียนอัลกอริทึมการเข้ารหัสลับ (เช่น p-Pollard) สำหรับโรงเรียนและเข้าชมกำแพงของจำนวนเต็มและความยาวของการเป็นตัวแทนอาร์เรย์

คำตอบ:


163

มีขีด จำกัด สองข้อทั้งสองไม่ได้บังคับใช้โดย C ++ แต่ใช้โดยฮาร์ดแวร์

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

ขีด จำกัด อื่นคือขีด จำกัด หน่วยความจำกายภาพ ยิ่งวัตถุในอาร์เรย์มีขนาดใหญ่เท่าไหร่ถึงขีด จำกัด นี้เร็วขึ้นเพราะหน่วยความจำเต็ม ยกตัวอย่างเช่นตัวvector<int>ของขนาดที่กำหนดnมักจะใช้เวลาหลายครั้งตามที่หน่วยความจำมากเป็นอาร์เรย์ชนิดvector<char>(ลบค่าคงที่ขนาดเล็ก) เนื่องจากมักจะมีขนาดใหญ่กว่าint charดังนั้น a vector<char>อาจมีรายการมากกว่าvector<int>ก่อนหน่วยความจำเต็ม นับเหมือนกันสำหรับอาร์เรย์แบบ C ดิบเหมือนและint[]char[]

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

นอกเหนือจากนั้น C ++ ไม่บังคับใช้ข้อ จำกัด ใด ๆ


20
นอกจากนี้โดยปกติคุณสามารถเข้าถึงขีด จำกัด ขนาดสแต็กได้อย่างง่ายดายโดยเฉพาะอย่างยิ่งหากใช้เธรดซึ่งเป็นการนำไปใช้เฉพาะอีกครั้ง
Alaric

@Alaric: จริง ฉันไม่ต้องการเจาะลึกข้อมูลจำเพาะของระบบมากเกินไปเพราะมันแตกต่างกันมากและฉันไม่มีความเชี่ยวชาญใด ๆ เลย
Konrad Rudolph

@ Konrad จุดที่น่าสนใจเกี่ยวกับตัวจัดสรรประเภทและไม่ใช่สิ่งที่ฉันรู้ ขอบคุณสำหรับข้อมูล.
SmacL

11
std :: size_t มักจะเป็นขนาดของตัวชี้ไม่ใช่ขนาดของจำนวนเต็มที่ใหญ่ที่สุดที่มีการสนับสนุนฮาร์ดแวร์เนทีฟในหน่วยคณิตศาสตร์จำนวนเต็ม ในทุก ๆ ระบบปฏิบัติการ x86 ที่ฉันใช้ size_t คือ 32 บิตสำหรับระบบปฏิบัติการ 32 บิตและ 64 บิตสำหรับระบบปฏิบัติการ 64 บิต
Mr Fooz

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

171

ไม่มีใครพูดถึงข้อ จำกัด เกี่ยวกับขนาดของกรอบสแต็

มีหน่วยความจำสองตำแหน่งที่สามารถจัดสรรได้:

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

ดังนั้นหากคุณจัดสรรอาเรย์แบบไดนามิก (ขีด จำกัด มีขนาดใหญ่และอธิบายรายละเอียดโดยโพสต์อื่น ๆ

int* a1 = new int[SIZE];  // SIZE limited only by OS/Hardware

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

int a2[SIZE]; // SIZE limited by COMPILER to the size of the stack frame

4
การจัดสรรอาร์เรย์ขนาดใหญ่ที่ต้องการไม่ได้อยู่ในสแต็กหรือกำหนดทั่วโลก แต่ผ่านการจัดสรรแบบไดนามิก (ผ่านnewหรือmalloc)
Thomas Matthews

1
@ Thomas Matthews: ไม่ได้อยู่ในโลกของฉัน วัตถุที่จัดสรรแบบไดนามิกต้องการการจัดการ ถ้ามันต้องการการจัดสรรแบบไดนามิกฉันจะใช้วัตถุสแต็คที่เป็นตัวแทนของบันทึกการจัดสรรแบบไดนามิกเช่น std :: vector
Martin York

2
มีกรณี cornor หนึ่งหายไป: Global Arraysในขณะที่ไม่ใช่ความงามและหลีกเลี่ยงที่ดีที่สุดเหล่านี้ไม่อยู่ภายใต้ข้อ จำกัด ของstackและคุณไม่ต้องการmalloc/ freeทำงานกับพวกเขา
ted

1
@ted ทำไมอาร์เรย์ทั่วโลกควร "หลีกเลี่ยงที่ดีที่สุด" ฉันคิดว่าคุณหมายถึงอาร์เรย์ที่ถูกจัดสรรแบบคงที่ ขอบเขตของพวกเขาไม่จำเป็นต้องเป็นระดับโลก ฉันจะเถียงว่ามันดีกว่าไดนามิกอาร์เรย์เพราะคุณสามารถใช้การกำหนดแอดเดรสแบบสัมบูรณ์กับพวกเขา (อย่างน้อยบน Linux) ซึ่งคุณไม่สามารถทำได้ด้วยอาร์เรย์ที่จัดสรรแบบไดนามิก
Z boson

2
จุดสำคัญมาก ฉันเพิ่งเจอโครงการโอเพ่นซอร์ส "คุณภาพการผลิต" ที่ให้ขนาดบัฟเฟอร์สูงสุดที่กำหนดค่าได้ บัฟเฟอร์ทั้งหมดได้รับการจัดสรรบนสแต็กดังนั้นการกำหนดค่าที่มีขนาดใหญ่พอจะทำให้โปรแกรมแยก segfault ทันทีเมื่อเริ่มต้น
aroth

13

เมื่อมองจากการใช้งานจริงมากกว่ามุมมองเชิงทฤษฎีบนระบบ Windows 32 บิตจำนวนหน่วยความจำรวมสูงสุดที่ใช้ได้สำหรับกระบวนการเดียวคือ 2 GB คุณสามารถทำลายขีด จำกัด ได้โดยไปที่ระบบปฏิบัติการ 64 บิตที่มีหน่วยความจำกายภาพมากขึ้น แต่การทำเช่นนี้หรือการมองหาทางเลือกนั้นขึ้นอยู่กับผู้ใช้และงบประมาณของคุณเป็นอย่างมาก นอกจากนี้คุณยังสามารถขยายมันค่อนข้างใช้ PAEได้บ้าง

ชนิดของอาร์เรย์มีความสำคัญมากเนื่องจากการจัดเรียงโครงสร้างเริ่มต้นในคอมไพเลอร์จำนวนมากคือ 8 ไบต์ซึ่งสิ้นเปลืองมากหากการใช้หน่วยความจำเป็นปัญหา หากคุณใช้ Visual C ++ เพื่อกำหนดเป้าหมาย Windows ให้ตรวจสอบชุด #pragma directive เพื่อเอาชนะสิ่งนี้

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

แก้ไข: ได้รับข้อมูลเพิ่มเติมเกี่ยวกับความต้องการที่แน่นอนของคุณความต้องการพื้นที่เก็บข้อมูลของคุณจะอยู่ระหว่าง 7.6 GB ถึง 76 GB ซึ่งไม่มีการบีบอัดซึ่งจะต้องใช้กล่อง 64 บิตที่ค่อนข้างแพงในการจัดเก็บ มันทำให้เกิดคำถามว่าทำไมคุณต้องการจัดเก็บข้อมูลในหน่วยความจำโดยที่หนึ่งสันนิษฐานสำหรับความเร็วในการเข้าถึงและเพื่อให้การเข้าถึงแบบสุ่ม วิธีที่ดีที่สุดในการจัดเก็บข้อมูลนี้นอกอาเรย์นั้นค่อนข้างดีมากตามวิธีที่คุณต้องการเข้าถึง หากคุณต้องการเข้าถึงสมาชิกอาเรย์แบบสุ่มสำหรับแอปพลิเคชันส่วนใหญ่มักจะมีวิธีการจัดกลุ่มกลุ่มข้อมูลที่มักเข้าถึงได้ในเวลาเดียวกัน ตัวอย่างเช่นใน GIS ขนาดใหญ่และฐานข้อมูลเชิงพื้นที่ข้อมูลมักได้รับการปูกระเบื้องตามพื้นที่ทางภูมิศาสตร์ ในเงื่อนไขการเขียนโปรแกรม C ++ คุณสามารถแทนที่โอเปอเรเตอร์ [] เพื่อดึงข้อมูลบางส่วนจากที่เก็บข้อมูลภายนอกตามต้องการ


1
มีการเรียกระบบที่อนุญาตการจัดสรรหน่วยความจำนอกพื้นที่โปรแกรม แต่นี่คือระบบปฏิบัติการและไม่ใช่แบบพกพา เราใช้มันในระบบฝังตัว
Thomas Matthews

4

ฉันจะเห็นด้วยกับข้างต้นว่าถ้าคุณ intializing อาร์เรย์ของคุณด้วย

 int myArray[SIZE] 

SIZE จะถูก จำกัด ด้วยขนาดของจำนวนเต็ม แต่คุณสามารถ malloc หน่วยความจำได้ตลอดเวลาและมีตัวชี้ขนาดใหญ่เท่าที่คุณต้องการตราบใดที่ malloc ไม่ส่งคืนค่า NULL


ฉันไม่แน่ใจว่าสิ่งนี้ไม่ถูกต้องหรือฉันเข้าใจผิดคุณหรืออย่างอื่น ตัวอย่างเช่นนี้จะถูกป้องกันโดยคอมไพเลอร์ MSVC17: int oops[INT_MAX]{0};มันสร้างC2148 - total size of array must not exceed 0x7fffffff bytes
kayleeFrye_onDeck

ด้วย 16GB DDR4 และเกี่ยวกับ66%หน่วยความจำที่ใช้ในปัจจุบันก่อนที่จะเปิดตัวแอพพลิเคของฉันเป็นแก้ปัญหาบน Windows 10 พร้อมด้วย VS2017 ฉันมีขีด จำกัด ไม่ได้กำหนดเกี่ยวกับวิธีการที่มีขนาดใหญ่ของ int 0อาร์เรย์ที่ฉันจะเริ่มต้นด้วย บางครั้งฉันสามารถทำมันด้วยองค์ประกอบ ~ 257k บางครั้งฉันได้รับสแต็คล้น ถ้าฉันเพิ่มอะไรลงในแอพของฉันนอกเหนือจาก main และ array ตัวเลขนั้นจะลดลง (ชัด) ฉันต้องทดลองเพื่อหาจำนวนนี้ดังนั้นฉันจึงไม่เห็นว่าการวัดนี้สามารถพึ่งพาได้อย่างไรเมื่อรู้ขอบเขตของทฤษฎีในสุญญากาศ
kayleeFrye_onDeck

4

ในการสรุปคำตอบให้ขยายออกและตอบคำถามของคุณโดยตรง:

ไม่ C ++ ไม่ได้กำหนดขอบเขตสำหรับขนาดของอาร์เรย์

แต่เนื่องจากต้องมีการจัดเก็บอาร์เรย์ไว้ในหน่วยความจำดังนั้นข้อ จำกัด เกี่ยวกับหน่วยความจำที่กำหนดโดยส่วนอื่น ๆ ของระบบคอมพิวเตอร์จึงถูกนำมาใช้ โปรดทราบว่าข้อ จำกัด เหล่านี้ไม่ได้เกี่ยวข้องโดยตรงกับขนาด (= จำนวนองค์ประกอบ) ของอาร์เรย์ แต่เป็นขนาด (= จำนวนหน่วยความจำที่ใช้) ขนาด ( D ) และในหน่วยความจำขนาด ( S ) ของอาร์เรย์จะไม่เหมือนกันเช่นที่พวกเขามีความสัมพันธ์กันโดยหน่วยความจำที่ถ่ายโดยองค์ประกอบเดียว ( E ): S = D * E

ตอนนี้Eขึ้นอยู่กับ:

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

นอกจากนี้โปรดทราบว่าโดยทั่วไปคุณจะได้รับข้อ จำกัด เกี่ยวกับหน่วยความจำที่แตกต่างกันโดยการจัดสรรข้อมูลอาร์เรย์บนสแต็ก (เป็นตัวแปรอัตโนมัติint t[N]:) หรือบนฮีป (การจัดสรรแบบไดนามิกด้วยmalloc()/ newหรือใช้กลไก STL) หรือในส่วนคงที่ของหน่วยความจำกระบวนการ ตัวแปรคง: static int t[N]) แม้ว่าเมื่อจัดสรรฮีปคุณยังต้องใช้หน่วยความจำจำนวนเล็กน้อยในสแต็กเพื่อจัดเก็บการอ้างอิงไปยังบล็อกหน่วยความจำที่จัดสรรฮีป (แต่นี่เป็นสิ่งที่ไม่สำคัญโดยปกติ)

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

แหล่งที่มาของข้อ จำกัด ขนาดหน่วยความจำมาจาก

  • จำนวนหน่วยความจำที่มีอยู่สำหรับกระบวนการ (ซึ่ง จำกัด ไว้ที่ 2 ^ 32 ไบต์สำหรับแอปพลิเคชันแบบ 32 บิตแม้ในเคอร์เนลระบบปฏิบัติการ 64 บิต)
  • การแบ่งหน่วยความจำกระบวนการ (เช่นจำนวนหน่วยความจำกระบวนการที่ออกแบบสำหรับสแต็กหรือฮีป)
  • การแตกแฟรกเมนต์ของหน่วยความจำกายภาพ (กระจัดกระจายหน่วยความจำอิสระขนาดเล็กจำนวนมากไม่สามารถใช้ได้กับการจัดเก็บโครงสร้างแบบเสาหินเดียว)
  • จำนวนหน่วยความจำกายภาพ
  • และจำนวนหน่วยความจำเสมือน

พวกเขาไม่สามารถ 'ปรับแต่ง' ที่ระดับแอปพลิเคชัน แต่คุณมีอิสระในการใช้คอมไพเลอร์ที่แตกต่างกัน (เพื่อเปลี่ยนขีด จำกัด ขนาดสแต็ก) หรือพอร์ตแอปพลิเคชันของคุณเป็น 64- บิตหรือพอร์ตไปยังระบบปฏิบัติการอื่น การกำหนดค่าหน่วยความจำเสมือนของเครื่อง (virtual? physical?)

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

ดังนั้นในที่สุด: ในขณะที่ C ++ ไม่ได้กำหนดขีด จำกัด ใด ๆ คุณยังต้องตรวจสอบเงื่อนไขที่เกี่ยวข้องกับหน่วยความจำที่ไม่พึงประสงค์เมื่อใช้รหัสของคุณ ... :-)


3

ตามคำตอบที่ยอดเยี่ยมมากมายที่ระบุไว้มีข้อ จำกัด มากมายที่ขึ้นอยู่กับคอมไพเลอร์รุ่น C ++ ระบบปฏิบัติการและคุณสมบัติคอมพิวเตอร์ของคุณ อย่างไรก็ตามฉันขอแนะนำสคริปต์ต่อไปนี้บน Python ที่ตรวจสอบขีด จำกัด บนเครื่องของคุณ

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

import os

cpp_source = 'int a[{}]; int main() {{ return 0; }}'

def check_if_array_size_compiles(size):
        #  Write to file 1.cpp
        f = open(name='1.cpp', mode='w')
        f.write(cpp_source.format(m))
        f.close()
        #  Attempt to compile
        os.system('g++ 1.cpp 2> errors')
        #  Read the errors files
        errors = open('errors', 'r').read()
        #  Return if there is no errors
        return len(errors) == 0

#  Make a binary search. Try to create array with size m and
#  adjust the r and l border depending on wheather we succeeded
#  or not
l = 0
r = 10 ** 50
while r - l > 1:
        m = (r + l) // 2
        if check_if_array_size_compiles(m):
                l = m
        else:
                r = m

answer = l + check_if_array_size_compiles(r)
print '{} is the maximum avaliable length'.format(answer)

คุณสามารถบันทึกลงในเครื่องและเปิดใช้งานและมันจะพิมพ์ขนาดสูงสุดที่คุณสามารถสร้าง สำหรับเครื่องของฉันมันคือ 2305843009213693951


2

สิ่งหนึ่งที่ฉันไม่คิดว่าได้รับการกล่าวถึงในคำตอบก่อนหน้า

ฉันมักจะรู้สึกถึง "กลิ่นเหม็น" ในแง่ของการฟื้นฟูเมื่อผู้คนใช้สิ่งต่าง ๆ ในการออกแบบของพวกเขา

นั่นเป็นอาร์เรย์ขนาดใหญ่และอาจไม่ใช่วิธีที่ดีที่สุดในการแสดงข้อมูลของคุณทั้งจากมุมมองประสิทธิภาพและมุมมองประสิทธิภาพ

เสียงเชียร์

ปล้น


คุณมีข้อเสนอแนะเกี่ยวกับสิ่งที่ฉันควรใช้หรือไม่?
luiss

หากคุณสามารถบอกเราได้ว่าข้อมูลที่คุณเก็บนั้นคืออะไรบางทีเราสามารถทำได้ (-:
Rob Wells

ขออภัย Luis การตอบกลับครั้งแรกของฉันช่างเยือกเย็นมาก มันจะถูกขับเคลื่อนด้วยลักษณะของข้อมูลของคุณ ความสัมพันธ์ของข้อมูลของคุณจะเป็นตัวขับเคลื่อนโมเดลที่คุณใช้เพื่อเป็นตัวแทนของข้อมูล จากนั้นการรวบรวมควรจะชัดเจนจากที่ ถ้าไม่ฉันจะกังวลเกี่ยวกับรูปแบบข้อมูล
Rob Wells

ไม่หยิ่งถึงฉัน: แล้วฐานข้อมูลแคชกับของเล่นแบบนี้ล่ะ? tweaktown.com/news/22066/…

2

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


ดูเพิ่มเติมสำหรับ Merge Sort บนอัลกอริทึมตัวอย่างเพื่อจัดการข้อมูลที่มีขนาดใหญ่เกินไปที่จะพอดีกับหน่วยความจำ
Thomas Matthews

2

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

1. การ จำกัด เวลาในการรวบรวม

โดยพื้นฐานแล้วคอมไพเลอร์ของคุณจะอนุญาตอะไร สำหรับ Visual C ++ 2017 บนกล่อง x64 Windows 10 นี่คือขีด จำกัด สูงสุดของฉันในการรวบรวมเวลาก่อนที่จะเกิดข้อ จำกัด 2GB

unsigned __int64 max_ints[255999996]{0};

ถ้าฉันทำสิ่งนี้แทน

unsigned __int64 max_ints[255999997]{0};

ฉันจะได้รับ:

Error C1126 automatic allocation exceeds 2G

ฉันไม่แน่ใจว่า 2G สัมพันธ์กับ255999996/ 7อย่างไร ฉัน googled ทั้งตัวเลขและสิ่งเดียวที่ฉันพบได้ที่อาจเกี่ยวข้องกันคือ * คำถาม & คำตอบเกี่ยวกับdcปัญหาความแม่นยำด้วย ไม่ว่าจะด้วยวิธีใดอาร์เรย์ที่คุณกำลังพยายามเติมจะต้องมีองค์ประกอบเท่าใด

2. การ จำกัด เวลาทำงาน

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

int main()
{
    int max_ints[257400]{ 0 };
    return 0;
}

แต่ถ้าฉันปรับแต่งมันเพียงเล็กน้อย ...

int main()
{
    int max_ints[257500]{ 0 };
    return 0;
}

ปัง! สแต็คล้น!

Exception thrown at 0x00007FF7DC6B1B38 in memchk.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000AA8DE03000). Unhandled exception at 0x00007FF7DC6B1B38 in memchk.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000AA8DE03000).

และเพื่อให้รายละเอียดเกี่ยวกับจุดแอพทั้งหมดของคุณนี่เป็นเรื่องดีที่จะไป:

int main()
{
    int maxish_ints[257000]{ 0 };
    int more_ints[400]{ 0 };
    return 0;
}  

แต่สิ่งนี้ทำให้เกิดการล้นสแต็ก:

int main()
{
    int maxish_ints[257000]{ 0 };
    int more_ints[500]{ 0 };
    return 0;
}  

1

ฉันประหลาดใจที่ฟังก์ชั่นสมาชิกmax_size ()ของstd :: vectorไม่ได้ถูกกล่าวถึงที่นี่

"ส่งคืนจำนวนสูงสุดขององค์ประกอบที่คอนเทนเนอร์สามารถเก็บได้เนื่องจากข้อ จำกัด ของการใช้งานระบบหรือไลบรารีเช่น std :: distance (start (), end ()) สำหรับคอนเทนเนอร์ที่ใหญ่ที่สุด"

เรารู้ว่าstd::vectorมีการใช้งานเป็นอาเรย์แบบไดนามิกภายใต้ประทุนดังนั้นmax_size()ควรให้การประมาณความยาวสูงสุดของอาเรย์แบบไดนามิกบนเครื่องของคุณอย่างใกล้ชิด

โปรแกรมต่อไปนี้สร้างตารางความยาวอาร์เรย์สูงสุดโดยประมาณสำหรับชนิดข้อมูลต่างๆ

#include <iostream>
#include <vector>
#include <string>
#include <limits>

template <typename T>
std::string mx(T e) {
    std::vector<T> v;
    return std::to_string(v.max_size());
}

std::size_t maxColWidth(std::vector<std::string> v) {
    std::size_t maxWidth = 0;

    for (const auto &s: v)
        if (s.length() > maxWidth)
            maxWidth = s.length();

    // Add 2 for space on each side
    return maxWidth + 2;
}

constexpr long double maxStdSize_t = std::numeric_limits<std::size_t>::max();

// cs stands for compared to std::size_t
template <typename T>
std::string cs(T e) {
    std::vector<T> v;
    long double maxSize = v.max_size();
    long double quotient = maxStdSize_t / maxSize;
    return std::to_string(quotient);
}

int main() {
    bool v0 = 0;
    char v1 = 0;

    int8_t v2 = 0;
    int16_t v3 = 0;
    int32_t v4 = 0;
    int64_t v5 = 0;

    uint8_t v6 = 0;
    uint16_t v7 = 0;
    uint32_t v8 = 0;
    uint64_t v9 = 0;

    std::size_t v10 = 0;
    double v11 = 0;
    long double v12 = 0;

    std::vector<std::string> types = {"data types", "bool", "char", "int8_t", "int16_t",
                                      "int32_t", "int64_t", "uint8_t", "uint16_t",
                                      "uint32_t", "uint64_t", "size_t", "double",
                                      "long double"};

    std::vector<std::string> sizes = {"approx max array length", mx(v0), mx(v1), mx(v2),
                                      mx(v3), mx(v4), mx(v5), mx(v6), mx(v7), mx(v8),
                                      mx(v9), mx(v10), mx(v11), mx(v12)};

    std::vector<std::string> quotients = {"max std::size_t / max array size", cs(v0),
                                          cs(v1), cs(v2), cs(v3), cs(v4), cs(v5), cs(v6),
                                          cs(v7), cs(v8), cs(v9), cs(v10), cs(v11), cs(v12)};

    std::size_t max1 = maxColWidth(types);
    std::size_t max2 = maxColWidth(sizes);
    std::size_t max3 = maxColWidth(quotients);

    for (std::size_t i = 0; i < types.size(); ++i) {
        while (types[i].length() < (max1 - 1)) {
            types[i] = " " + types[i];
        }

        types[i] += " ";

        for  (int j = 0; sizes[i].length() < max2; ++j)
            sizes[i] = (j % 2 == 0) ? " " + sizes[i] : sizes[i] + " ";

        for  (int j = 0; quotients[i].length() < max3; ++j)
            quotients[i] = (j % 2 == 0) ? " " + quotients[i] : quotients[i] + " ";

        std::cout << "|" << types[i] << "|" << sizes[i] << "|" << quotients[i] << "|\n";
    }

    std::cout << std::endl;

    std::cout << "N.B. max std::size_t is: " <<
        std::numeric_limits<std::size_t>::max() << std::endl;

    return 0;
}

ใน macOS ของฉัน (เวอร์ชั่นเสียงดังกราว 5.0.1) ฉันได้รับสิ่งต่อไปนี้:

|  data types | approx max array length | max std::size_t / max array size |
|        bool |   9223372036854775807   |             2.000000             |
|        char |   9223372036854775807   |             2.000000             |
|      int8_t |   9223372036854775807   |             2.000000             |
|     int16_t |   9223372036854775807   |             2.000000             |
|     int32_t |   4611686018427387903   |             4.000000             |
|     int64_t |   2305843009213693951   |             8.000000             |
|     uint8_t |   9223372036854775807   |             2.000000             |
|    uint16_t |   9223372036854775807   |             2.000000             |
|    uint32_t |   4611686018427387903   |             4.000000             |
|    uint64_t |   2305843009213693951   |             8.000000             |
|      size_t |   2305843009213693951   |             8.000000             |
|      double |   2305843009213693951   |             8.000000             |
| long double |   1152921504606846975   |             16.000000            |

N.B. max std::size_t is: 18446744073709551615

ในideone gcc 8.3ฉันได้รับ:

|  data types | approx max array length | max std::size_t / max array size |
|        bool |   9223372036854775744   |             2.000000             |
|        char |   18446744073709551615  |             1.000000             |
|      int8_t |   18446744073709551615  |             1.000000             |
|     int16_t |   9223372036854775807   |             2.000000             |
|     int32_t |   4611686018427387903   |             4.000000             |
|     int64_t |   2305843009213693951   |             8.000000             |
|     uint8_t |   18446744073709551615  |             1.000000             |
|    uint16_t |   9223372036854775807   |             2.000000             |
|    uint32_t |   4611686018427387903   |             4.000000             |
|    uint64_t |   2305843009213693951   |             8.000000             |
|      size_t |   2305843009213693951   |             8.000000             |
|      double |   2305843009213693951   |             8.000000             |
| long double |   1152921504606846975   |             16.000000            |

N.B. max std::size_t is: 18446744073709551615

ควรสังเกตว่านี่เป็นข้อ จำกัด ทางทฤษฎีและในคอมพิวเตอร์ส่วนใหญ่คุณจะมีหน่วยความจำไม่เพียงพอก่อนที่จะถึงขีด จำกัด นี้ ตัวอย่างเช่นเราจะเห็นว่าสำหรับประเภทcharในจำนวนสูงสุดขององค์ประกอบเท่ากับสูงสุดของgcc std::size_tลองทำสิ่งนี้เราจะได้รับข้อผิดพลาด:

prog.cpp: In function int main()’:
prog.cpp:5:61: error: size of array is too large
  char* a1 = new char[std::numeric_limits<std::size_t>::max()];

สุดท้ายตามที่ @MartinYork ชี้ให้เห็นว่าสำหรับอาร์เรย์แบบคงที่ขนาดสูงสุดจะถูก จำกัด โดยขนาดของสแต็กของคุณ


0

ดังที่มีการระบุไว้แล้วขนาดของอาเรย์จะถูก จำกัด โดยฮาร์ดแวร์และระบบปฏิบัติการของคุณ (man ulimit) แม้ว่าซอฟต์แวร์ของคุณอาจถูก จำกัด ด้วยความคิดสร้างสรรค์ของคุณเท่านั้น ตัวอย่างเช่นคุณสามารถจัดเก็บ "อาร์เรย์" ของคุณไว้ในดิสก์ได้หรือไม่ คุณต้องการ ints ที่ยาวนานหรือไม่? คุณต้องการอาร์เรย์ที่หนาแน่นจริง ๆ หรือไม่? คุณจำเป็นต้องมีอาร์เรย์เลยหรือไม่?

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


2
อืมดิสก์อาร์เรย์ ... ได้ยินใครของหน่วยความจำเสมือน ระบบปฏิบัติการที่รองรับหน่วยความจำเสมือนจะเริ่มใช้อุปกรณ์ภายนอกสำหรับหน่วยความจำเช่นฮาร์ดดิสก์และสลับชิ้นส่วนกับหน่วยความจำภายใน
Thomas Matthews

0

ฉันจะไปรอบ ๆ นี้โดยการสร้างอาร์เรย์แบบไดนามิก 2d:

long long** a = new long long*[x];
for (unsigned i = 0; i < x; i++) a[i] = new long long[y];

เพิ่มเติมเกี่ยวกับเรื่องนี้ที่นี่https://stackoverflow.com/a/936702/3517001

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