ความผิดพลาดในการแบ่งกลุ่มในขนาดอาร์เรย์ขนาดใหญ่


116

รหัสต่อไปนี้ทำให้ฉันมีข้อผิดพลาดในการแบ่งกลุ่มเมื่อทำงานบนเครื่อง 2Gb แต่ทำงานบนเครื่อง 4GB

int main()
{
   int c[1000000];
   cout << "done\n";
   return 0;
}

ขนาดของอาร์เรย์เป็นเพียง 4Mb มีการ จำกัด ขนาดของอาร์เรย์ที่สามารถใช้ใน c ++ หรือไม่?

คำตอบ:


130

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

หากคุณจัดสรรอาร์เรย์บนฮีปคุณน่าจะใช้ได้โดยสมมติว่าเครื่องของคุณมีหน่วยความจำเพียงพอ

int* array = new int[1000000];

แต่จำไว้ว่าสิ่งนี้จะทำให้คุณต้องใช้delete[]อาร์เรย์ ทางออกที่ดีกว่าคือใช้std::vector<int>และปรับขนาดเป็น 1000000 องค์ประกอบ


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

18
รหัสที่กำหนดจะจัดสรรบนสแต็กเนื่องจากถูกระบุเป็นอาร์เรย์ที่มีจำนวนองค์ประกอบคงที่ในเวลาคอมไพล์ ค่าจะถูกใส่ไว้ในฮีปด้วย malloc ใหม่ ฯลฯ เท่านั้น
Seth Johnson

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

@ ชาร์ลส์ทำไมเราสามารถจัดสรรหน่วยความจำเพิ่มเติมจากฮีปไม่ใช่จากสแต็ค? จากความเข้าใจของฉันทั้ง stack และ heap จะเคลื่อนที่ไปในทิศทางตรงกันข้ามในพื้นที่แอดเดรสที่จัดสรรในหน่วยความจำ
saurabh agarwal

2
@saurabhagarwal กองไม่ขยับ มันไม่ได้เป็นพื้นที่หน่วยความจำที่อยู่ติดกัน ตัวจัดสรรจะส่งคืนบล็อกหน่วยความจำฟรีที่เหมาะกับขนาดของคุณสแต็กและฮีปอยู่ที่ไหน?
phuclv

56

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

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

สิ่งนี้จะจัดสรรในส่วน BSS ซึ่งเป็นส่วนหนึ่งของฮีป:

static int c[1000000];
int main()
{
   cout << "done\n";
   return 0;
}

สิ่งนี้จะจัดสรรในเซ็กเมนต์ DATA ซึ่งเป็นส่วนหนึ่งของฮีปด้วย:

int c[1000000] = {};
int main()
{
   cout << "done\n";
   return 0;
}

สิ่งนี้จะจัดสรรในตำแหน่งที่ไม่ระบุบางส่วนในฮีป:

int main()
{
   int* c = new int[1000000];
   cout << "done\n";
   return 0;
}

หากคุณใช้รูปแบบที่สามโดยจัดสรรบนฮีปอย่าลืมลบ [] ตัวชี้ในบางขั้นตอนมิฉะนั้นหน่วยความจำจะรั่ว หรือมองเป็นตัวชี้อัจฉริยะ
davidA

8
@meowsqueak แน่นอนมันคือการปฏิบัติที่ดีที่จะทุกที่ที่คุณจัดสรรด้วยdelete newแต่ถ้าคุณแน่ใจว่าคุณจัดสรรหน่วยความจำเพียงครั้งเดียว (เช่นเดียวกับใน main) ก็ไม่จำเป็นอย่างยิ่ง - รับประกันว่าหน่วยความจำจะถูกปลดปล่อยเมื่อออกจาก main แม้จะไม่ชัดเจนdeleteก็ตาม
Gunther Piez

'at'drhirsch (คุณจะทำ at-character ได้อย่างไร?) - ใช่ความคิดเห็นที่ยุติธรรม เนื่องจาก OP ปรากฏเป็นภาษาใหม่ฉันแค่ต้องการให้แน่ใจว่าพวกเขาและคนอื่น ๆ ที่เห็นคำตอบที่ดีของคุณได้รับทราบถึงผลกระทบของตัวเลือกที่สามหากใช้โดยทั่วไป
davidA

15

นอกจากนี้หากคุณใช้งานในระบบ UNIX & Linux ส่วนใหญ่คุณสามารถเพิ่มขนาดสแต็กชั่วคราวโดยใช้คำสั่งต่อไปนี้:

ulimit -s unlimited

แต่ระวังหน่วยความจำเป็นทรัพยากรที่ จำกัด และด้วยพลังอันยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ยิ่งใหญ่ :)


1
นี่เป็นวิธีแก้ปัญหา แต่ฉันแนะนำให้ทุกคนระมัดระวังอย่างยิ่งเมื่อลบขีด จำกัด เริ่มต้นนี้เกี่ยวกับขนาดสแต็กของโปรแกรม คุณจะพบว่าประสิทธิภาพไม่เพียงลดลงอย่างรุนแรง แต่ระบบของคุณอาจพัง ตัวอย่างเช่นฉันพยายามจัดเรียงอาร์เรย์ด้วยองค์ประกอบจำนวนเต็ม 16,000,000 รายการด้วย Quicksort บนเครื่องที่มี RAM 4GB และระบบของฉันเกือบจะถูกฆ่า LOL
rbaleksandar

@rbaleksandar ฉันคิดว่าคุณ ~ โปรแกรม 16MB เกือบจะฆ่าเครื่องของคุณเพราะคุณทำงานกับอาร์เรย์หลายชุด (อาจเป็นหนึ่งชุดต่อการเรียกใช้ฟังก์ชัน) ลองใช้การใช้งานหน่วยความจำเพิ่มเติม;)
RSFalcon7

ฉันค่อนข้างมั่นใจว่าการจัดการอาร์เรย์นั้นใช้ได้เนื่องจากฉันส่งผ่านโดยการอ้างอิงไม่ใช่ตามค่า สิ่งเดียวกันนี้เกิดขึ้นกับ bubbleort นรกแม้ว่าการใช้ Quicksort ของฉันจะดูด Bubblesort เป็นสิ่งที่คุณไม่สามารถใช้งานได้อย่างไม่ถูกต้อง LOL
rbaleksandar

ฮ่า ๆ คุณสามารถลองเรียงลำดับ radix หรือใช้ std :: sort :)
RSFalcon7

1
ไม่มีโอกาส. เป็นการกำหนดห้องปฏิบัติการ : D
rbaleksandar

3

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


3

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

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