2011-12-23 30 views
6

Tôi vừa đọc xong K & R, và đó là tất cả C mà tôi biết. Tất cả các biên dịch của tôi được thực hiện từ dòng lệnh của Windows bằng cách sử dụng MinGW, và tôi không có kiến ​​thức về các phương pháp gỡ lỗi nâng cao (do đó "nhận xét gỡ lỗi ghetto" trong chương trình thứ 2 của tôi bên dưới).Hiểu phân bổ bộ nhớ, chương trình thử nghiệm bị lỗi

Tôi đang cố gắng thực hiện một vài chương trình thử nghiệm nhỏ để giúp tôi hiểu rõ hơn về cách phân bổ bộ nhớ hoạt động. Các chương trình cặp đôi đầu tiên này không sử dụng malloc hoặc miễn phí, tôi chỉ muốn xem bộ nhớ được cấp phát và phân bổ như thế nào cho các mảng tiêu chuẩn cục bộ cho một hàm. Ý tưởng là tôi xem quá trình chạy RAM của tôi đang sử dụng để xem nó có tương ứng với những gì tôi hiểu không. Đối với chương trình đầu tiên dưới đây, nó hoạt động như tôi mong đợi. Hàm alloc_one_meg() phân bổ và khởi tạo 250.000 số nguyên 4 byte, nhưng MB đó được phân bổ ngay sau khi hàm trả về. Vì vậy, nếu tôi gọi hàm đó 1000000 lần liên tiếp, tôi sẽ không bao giờ thấy mức sử dụng RAM của mình vượt quá 1MB. Và nó hoạt động.

#include <stdio.h> 
#include <stdlib.h> 

void alloc_one_meg() { 
    int megabyte[250000]; 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
} 

main() 
{ 
    int i; 
    for (i=0; i<1000000; i++) { 
     alloc_one_meg(); 
    } 
} 

Đối với chương trình thứ hai này dưới đây, ý tưởng là để không cho phép các chức năng để thoát ra, để có 1.000 bản sao của cùng một chức năng chạy cùng một lúc, mà tôi thực hiện với đệ quy. Lý thuyết của tôi là chương trình sẽ tiêu thụ 1GB RAM trước khi nó được cấp phát tất cả sau khi đệ quy kết thúc. Tuy nhiên, nó không vượt qua vòng lặp thứ 2 thông qua đệ quy (xem bình luận gỡ lỗi ghetto của tôi). Chương trình bị treo với một thông báo khá không mang tính thông tin (cho tôi) (một cửa sổ pop-up nói ____. Exe đã gặp phải một vấn đề). Thông thường tôi luôn có thể đi đến đáy của những thứ với phương pháp gỡ lỗi ghetto của tôi ... nhưng nó không hoạt động ở đây. Tôi bối rối. Vấn đề với mã này là gì? Cảm ơn!

#include <stdio.h> 
#include <stdlib.h> 

int j=0; 

void alloc_one_meg() { 
    int megabyte[250000]; 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
    j++; 
    printf("Loop %d\n", j); // ghetto debug 
    if (j<1000) { 
     alloc_one_meg(); 
    } 
} 

main() 
{ 
    alloc_one_meg(); 
} 

Câu hỏi tiếp theo được đăng here.

+2

Và bây giờ bạn gặp sự cố tràn ngăn xếp, bạn có hiểu biết rõ hơn về bộ nhớ. Buồn cười mọi thứ diễn ra như thế nào. –

+2

Yup, tôi mới lập trình, nhưng không phải là mới đối với ý tưởng thử nghiệm. Tôi là một kỹ sư và một người sử dụng phần mềm nặng, và tôi biết rất rõ rằng việc phá vỡ mọi thứ là cách tốt nhất để hiểu họ! :-) – The111

Trả lời

3

Bạn đang chạy vào tràn ngăn xếp.

Biến lưu trữ tự động cục bộ (chẳng hạn như megabyte) được cấp phát trên ngăn xếp, có số lượng giới hạn không gian. malloc phân bổ trên heap, cho phép phân bổ lớn hơn nhiều.

Bạn có thể đọc thêm ở đây:

http://en.wikipedia.org/wiki/Stack_overflow

(Tôi nên lưu ý rằng ngôn ngữ C không xác định được nơi bộ nhớ được phân bổ - stack và heap là chi tiết thực hiện)

+4

Làm thế nào tuyệt vời, tôi đã học về tràn ngăn xếp trên stackoverflow.com. Tôi nên đăng bài này lên meta! Cảm ơn lời giải thích và liên kết. – The111

+0

malloc() không có dung lượng lớn hơn - xem kết xuất từ ​​dumpbin và số lượng dành riêng cho "đống". –

2

Kích thước của stack trong một chương trình Windows thường là khoảng 1 MB, do đó, trên đệ quy thứ hai, bạn đang tràn ngăn xếp. Bạn không nên bố trí mảng lớn như vậy trên stack, sử dụng mallocfree để phân bổ và deallocate bộ nhớ trên heap (không có cách nào để có được xung quanh malloc Đối với kích thước như của mảng):

void alloc_one_meg() { 
    int *megabyte = malloc(sizeof(int) * 250000); // allocate space for 250000 
                // ints on the heap 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
    j++; 
    printf("Loop %d\n", j); // ghetto debug 
    if (j<1000) { 
     alloc_one_meg(); 
    } 

    free(megabyte); // DO NOT FORGET THIS 
} 

Điều đó nói rằng , bạn thực sự có thể thay đổi kích thước ngăn xếp của một chương trình và làm cho nó lớn hơn (mặc dù tôi chỉ làm như vậy là một bài tập giáo dục, không phải trong mã sản xuất). Đối với Visual Studio, bạn có thể use the /F compiler option và trên linux, bạn có thể sử dụng setrlimit(3). Tôi không chắc chắn những gì để sử dụng với MinGW mặc dù.

+0

Ông nói rằng ông không muốn sử dụng malloc/miễn phí. – Pubby

+2

@Pubby ông không thể không sử dụng chúng –

+0

Một phần của mục đích lớn hơn của loạt bài kiểm tra này là để giúp tôi hiểu mục đích của malloc và miễn phí. Tôi muốn chạy một vài bài kiểm tra đầu tiên mà không có chúng, sau đó một vài bài kiểm tra với chúng. Tôi biết rằng các biến stack cục bộ có cuộc sống liên quan đến chức năng nhập/thoát, trong khi các biến heap có tuổi thọ liên quan đến malloc/free, nhưng tôi đã không nhận ra stack có giới hạn nhỏ như vậy. Vì vậy, tôi đã học được một điều lớn với bài kiểm tra này. :-) – The111

0

StackOverflow. Đây có phải là một câu hỏi lừa?

+0

Không, tôi chỉ là một noob. Tôi đang học rất nhanh rằng có rất nhiều điều về C mà tôi cần phải biết rằng tôi không thể nhận được từ K & R (như tôi đã nói, nguồn kiến ​​thức duy nhất của tôi cho đến nay).Đâu là một nơi tốt để tìm hiểu về kiến ​​thức có thể ngăn cản tôi hỏi một câu hỏi như vậy? Stack/heap, đó là loại điều (những khái niệm không có trong K & R, và tôi nhận ra lý do tại sao). – The111

1

Bộ nhớ bạn đang phân bổ thông qua các cuộc gọi chức năng đệ quy được cấp phát từ ngăn xếp. Tất cả bộ nhớ ngăn xếp phải tiếp giáp nhau.Khi quá trình của bạn bắt đầu một luồng, Windows sẽ đặt trước một vùng không gian địa chỉ bộ nhớ ảo cho ngăn xếp của luồng đó. Dung lượng bộ nhớ được đặt trước được chỉ định trong "tiêu đề PE" của tệp EXE. PE là viết tắt của "Portable Executable."

Sử dụng tiện ích dumpbin bao gồm trong Visual Studio, với chính nó (dumpbin.exe) như các tập tin đầu vào:

dumpbin /headers dumpbin.exe

... có một số đầu ra, và sau đó:

 100000 size of stack reserve 
     2000 size of stack commit 

"100000" là số hệ thập lục phân bằng 1,048,576, vì vậy, số này đại diện cho khoảng 1MB.

Nói cách khác, hệ điều hành sẽ chỉ đặt trước phạm vi địa chỉ 1MB cho ngăn xếp. Khi phạm vi địa chỉ đó được sử dụng hết, Windows có thể hoặc không thể phân bổ thêm các dải bộ nhớ liên tiếp để tăng ngăn xếp. Kết quả phụ thuộc vào dải địa chỉ tiếp giáp có sẵn hay không. Nó là rất khó có thể, do các phân bổ khác Windows được thực hiện khi thread bắt đầu.

Để phân bổ số lượng bộ nhớ ảo tối đa trong Windows, hãy sử dụng nhóm chức năng VirtualAlloc.

Các vấn đề liên quan