Lỗi phân đoạn trên kích thước mảng lớn


116

Đoạn mã sau cho tôi một lỗi phân đoạn khi chạy trên máy 2Gb, nhưng hoạt động trên máy 4GB.

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

Kích thước của mảng chỉ là 4Mb. Có giới hạn về kích thước của một mảng có thể được sử dụng trong c ++ không?

Câu trả lời:


130

Có lẽ bạn chỉ nhận được một ngăn xếp tràn ở đây. Mảng quá lớn để vừa với không gian địa chỉ ngăn xếp chương trình của bạn.

Nếu bạn phân bổ mảng trên heap, bạn sẽ ổn, giả sử máy của bạn có đủ bộ nhớ.

int* array = new int[1000000];

Nhưng hãy nhớ rằng điều này sẽ yêu cầu bạn đến delete[]mảng. Một giải pháp tốt hơn sẽ là sử dụng std::vector<int>và thay đổi kích thước của nó thành 1000000 phần tử.


3
Cảm ơn câu trả lời, nhưng bạn có thể giải thích cho tôi tại sao mảng được phân bổ trên ngăn xếp và tại sao không có trong bộ nhớ chương trình chính.
Mayank

18
Mã đã cho phân bổ trên ngăn xếp vì nó được chỉ định là một mảng có số lượng phần tử không đổi tại thời gian biên dịch. Các giá trị chỉ được đưa vào đống với malloc, mới, v.v.
Seth Johnson

6
Tất cả các biến tự động được phân bổ trên ngăn xếp. Nếu bạn nhìn vào sự phân tách, bạn sẽ thấy kích thước của các biến cục bộ của bạn được trừ khỏi con trỏ ngăn xếp. Khi bạn gọi malloc hoặc calloc hoặc bất kỳ bộ nhớ nào, các chức năng sẽ đi và tìm các khối bộ nhớ đủ lớn để thỏa mãn yêu cầu của bạn.
chạy lại

@Charles tại sao chúng ta có thể phân bổ thêm bộ nhớ từ heap chứ không phải từ stack? theo hiểu biết của tôi, cả stack và heap di chuyển theo hướng ngược lại trong không gian địa chỉ được phân bổ trong bộ nhớ.
saurabh agarwal

2
@saurabhagarwal Heap không di chuyển. Nó thậm chí không phải là một vùng bộ nhớ liền kề. Bộ cấp phát chỉ đơn giản trả về một khối bộ nhớ miễn phí phù hợp với yêu cầu kích thước của bạn Ngăn xếp và đống ở đâu và ở đâu?
phuclv

56

Trong C hoặc C ++, các đối tượng cục bộ thường được phân bổ trên ngăn xếp. Bạn đang phân bổ một mảng lớn trên ngăn xếp, nhiều hơn ngăn xếp có thể xử lý, vì vậy bạn đang nhận được một stackoverflow.

Đừng phân bổ cục bộ trên stack, thay vào đó hãy sử dụng một số vị trí khác. Điều này có thể đạt được bằng cách làm cho đối tượng toàn cầu hoặc phân bổ nó trên heap toàn cầu . Các biến toàn cục đều ổn, nếu bạn không sử dụng từ bất kỳ đơn vị biên dịch nào khác. Để đảm bảo điều này không xảy ra do tai nạn, hãy thêm một bộ xác định lưu trữ tĩnh, nếu không thì chỉ cần sử dụng heap.

Điều này sẽ phân bổ trong phân khúc BSS, một phần của heap:

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

Điều này sẽ phân bổ trong phân đoạn DATA, cũng là một phần của heap:

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

Điều này sẽ phân bổ tại một số vị trí không xác định trong heap:

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

Nếu bạn sử dụng mẫu thứ ba, phân bổ trên heap, đừng quên xóa [] con trỏ ở giai đoạn nào đó hoặc bạn sẽ bị rò rỉ bộ nhớ. Hoặc nhìn vào con trỏ thông minh.
davidA

8
@meowsqueak Tất nhiên đó là cách thực hành tốt deleteở mọi nơi bạn phân bổ new. Nhưng nếu bạn chắc chắn rằng bạn chỉ cấp phát bộ nhớ một lần (như trong main) thì hoàn toàn không cần thiết - bộ nhớ được đảm bảo sẽ được giải phóng khi thoát khỏi main ngay cả khi không rõ ràng delete.
Gunther Piez

'at'drhirsch (làm thế nào để bạn làm nhân vật nào?) - vâng, nhận xét công bằng. Vì OP xuất hiện mới với ngôn ngữ mà tôi chỉ muốn đảm bảo rằng họ và bất kỳ ai khác nhìn thấy câu trả lời tốt của bạn, đã nhận thức được ý nghĩa của tùy chọn thứ ba nếu thường được sử dụng.
davidA

15

Ngoài ra, nếu bạn đang chạy trong hầu hết các hệ thống UNIX & Linux, bạn có thể tạm thời tăng kích thước ngăn xếp bằng lệnh sau:

ulimit -s unlimited

Nhưng hãy cẩn thận, bộ nhớ là một nguồn tài nguyên hạn chế và với sức mạnh lớn sẽ có trách nhiệm lớn :)


1
Đây là giải pháp nhưng tôi khuyên tất cả phải cực kỳ thận trọng khi xóa giới hạn mặc định này trên kích thước ngăn xếp của chương trình. Bạn sẽ trải nghiệm không chỉ giảm hiệu suất nghiêm trọng mà hệ thống của bạn có thể gặp sự cố. Ví dụ, tôi đã cố gắng sắp xếp một mảng với 16 000 000 phần tử nguyên với quicksort trên một máy có RAM 4GB và hệ thống của tôi gần như bị giết. LOL
rbaleksandar

@rbaleksandar Tôi nghĩ rằng bạn ~ chương trình 16MB gần như giết chết máy tính của bạn bởi vì bạn đang làm việc với một số bản sao của mảng thử một bộ nhớ hơn thực hiện nhận thức được;) (có thể là một cho mỗi cuộc gọi chức năng?)
RSFalcon7

Tôi khá chắc chắn rằng việc xử lý mảng là ổn vì tôi chuyển qua tham chiếu chứ không phải theo giá trị. Điều tương tự xảy ra với bubbleort. Chết tiệt, ngay cả khi việc tôi thực hiện quicksort hút bubbleort là điều mà bạn không thể thực hiện không chính xác. LOL
rbaleksandar

LOL bạn có thể thử sắp xếp radix hoặc đơn giản là sử dụng std :: sort :)
RSFalcon7

1
Không có cơ hội. Đó là một bài tập trong phòng thí nghiệm. : D
rbaleksandar

3

Mảng của bạn đang được phân bổ trên ngăn xếp trong trường hợp này cố gắng phân bổ một mảng có cùng kích thước bằng phân bổ.


3

Bởi vì bạn lưu trữ các mảng trong ngăn xếp. Bạn nên lưu trữ nó trong đống. Xem liên kết này để hiểu khái niệm của heap và stack.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.