Sự khác biệt giữa cấp phát bộ nhớ tĩnh và cấp phát bộ nhớ động


Câu trả lời:


91

Có ba loại phân bổ - tĩnh, tự động và động.

Phân bổ tĩnh có nghĩa là bộ nhớ cho các biến của bạn được cấp phát khi chương trình bắt đầu. Kích thước được cố định khi chương trình được tạo. Nó áp dụng cho các biến toàn cục, biến phạm vi tệp và các biến đủ điều kiệnstatic hàm bên trong được xác định.

Cấp phát bộ nhớ tự động xảy ra cho các biến (không tĩnh) được xác định bên trong các hàm và thường được lưu trữ trên ngăn xếp (mặc dù tiêu chuẩn C không bắt buộc phải sử dụng ngăn xếp). Bạn không phải dự trữ thêm bộ nhớ bằng cách sử dụng chúng, nhưng mặt khác, cũng có quyền kiểm soát hạn chế đối với thời gian tồn tại của bộ nhớ này. Vd: biến tự động trong một hàm chỉ ở đó cho đến khi hàm kết thúc.

void func() {
    int i; /* `i` only exists during `func` */
}

Cấp phát bộ nhớ động hơi khác một chút. Bây giờ bạn kiểm soát kích thước chính xác và thời gian tồn tại của các vị trí bộ nhớ này. Nếu bạn không giải phóng nó, bạn sẽ gặp phải tình trạng rò rỉ bộ nhớ, có thể khiến ứng dụng của bạn gặp sự cố, vì tại một số thời điểm, hệ thống không thể phân bổ thêm bộ nhớ.

int* func() {
    int* mem = malloc(1024);
    return mem;
}

int* mem = func(); /* still accessible */

Trong ví dụ trên, bộ nhớ được cấp phát vẫn hợp lệ và có thể truy cập được, mặc dù chức năng đã kết thúc. Khi bạn làm xong bộ nhớ, bạn phải giải phóng nó:

free(mem);

2
Chắc chắn bạn có quyền kiểm soát thời gian tồn tại của các biến ... bạn là người quyết định phạm vi, phải không?
Luchian Grigore

Tất nhiên, nhưng đó không phải là ý của tôi. Bạn không thể kéo dài thời gian tồn tại của các biến để tồn tại lâu hơn phạm vi của nó. Nhưng có lẽ tôi nên làm rõ điều đó trong câu trả lời của mình. Cảm ơn
Constantinius

5
-1 Câu trả lời này là sai. Bạn nhầm lẫn giữa biến tĩnh và biến tự động .
brice

2
Câu của riêng bạn có nội dung: " Phân bổ tĩnh có nghĩa là bộ nhớ cho các biến của bạn được cấp phát tự động " Điều này sai . Hãy xem trang hướng dẫn sử dụng cho libc của GNU nói gì về nó.
brice

1
@EliBendersky Nó đã được diễn đạt lại ngay bây giờ. Kiểm tra xem nó có đúng bây giờ không.
Suraj Jain

116

Đây là một câu hỏi phỏng vấn tiêu chuẩn:

Phân bổ bộ nhớ động

Bộ nhớ được cấp phát trong thời gian chạy bằng cách sử dụng calloc(), malloc()và bạn bè. Đôi khi nó còn được gọi là bộ nhớ 'heap', mặc dù nó không liên quan gì đến ref cấu trúc dữ liệu heap .

int * a = malloc(sizeof(int));

Bộ nhớ đống sẽ tồn tại cho đến khi free() được gọi. Nói cách khác, bạn kiểm soát thời gian tồn tại của biến.

Phân bổ bộ nhớ tự động

Đây là cái thường được gọi là bộ nhớ 'ngăn xếp' và được cấp phát khi bạn nhập một phạm vi mới (thường là khi một hàm mới được đẩy lên ngăn xếp cuộc gọi). Khi bạn di chuyển ra khỏi phạm vi, các giá trị của địa chỉ bộ nhớ tự động không được xác định và việc truy cập chúng là một lỗi .

int a = 43;

Lưu ý rằng phạm vi không nhất thiết có nghĩa là chức năng. Phạm vi có thể lồng trong một hàm và biến sẽ chỉ nằm trong phạm vi trong khối mà nó được khai báo. Cũng lưu ý rằng nơi bộ nhớ này được cấp phát không được chỉ định. (Bình tĩnh hệ thống nó sẽ nằm trên ngăn xếp hoặc đăng ký để tối ưu hóa)

Cấp phát bộ nhớ tĩnh

Được cấp phát tại thời điểm biên dịch * và thời gian tồn tại của một biến trong bộ nhớ tĩnh là thời gian tồn tại của chương trình .

Trong C, bộ nhớ tĩnh có thể được cấp phát bằng cách sử dụng static từ khóa. Phạm vi chỉ là đơn vị biên dịch.

Mọi thứ trở nên thú vị hơn khi externtừ khóa được xem xét . Khi một externbiến được xác định , trình biên dịch sẽ cấp phát bộ nhớ cho nó. Khi một externbiến được khai báo , trình biên dịch yêu cầu biến đó phải được định nghĩa ở nơi khác. Không khai báo / xác định externbiến sẽ gây ra sự cố liên kết, trong khi không khai báo / định nghĩastatic biến sẽ gây ra vấn đề biên dịch.

trong phạm vi tệp, từ khóa tĩnh là tùy chọn (bên ngoài một hàm):

int a = 32;

Nhưng không phải trong phạm vi hàm (bên trong một hàm):

static int a = 32;

Về mặt kỹ thuật, externstaticlà hai lớp biến riêng biệt trong C.

extern int a; /* Declaration */
int a; /* Definition */

* Lưu ý về cấp phát bộ nhớ tĩnh

Hơi khó hiểu khi nói rằng bộ nhớ tĩnh được cấp phát tại thời điểm biên dịch, đặc biệt nếu chúng ta bắt đầu xem xét rằng máy biên dịch và máy chủ có thể không giống nhau hoặc thậm chí có thể không trên cùng một kiến ​​trúc.

Có thể tốt hơn khi nghĩ rằng việc cấp phát bộ nhớ tĩnh được xử lý bởi trình biên dịch hơn là cấp phát tại thời điểm biên dịch .

Ví dụ, trình biên dịch có thể tạo ra một data phần trong tệp nhị phân đã biên dịch và khi chương trình được tải vào bộ nhớ, địa chỉ trongdataphân đoạn của chương trình sẽ được sử dụng làm vị trí của bộ nhớ được cấp phát. Điều này có nhược điểm rõ ràng là làm cho tệp nhị phân được biên dịch rất lớn nếu sử dụng nhiều bộ nhớ tĩnh. Có thể viết một tệp nhị phân nhiều gigabyte được tạo từ ít hơn nửa tá dòng mã. Một tùy chọn khác là để trình biên dịch đưa mã khởi tạo sẽ cấp phát bộ nhớ theo một số cách khác trước khi chương trình được thực thi. Mã này sẽ thay đổi tùy theo nền tảng và hệ điều hành đích. Trong thực tế, các trình biên dịch hiện đại sử dụng heuristics để quyết định sử dụng tùy chọn nào trong số các tùy chọn này. Bạn có thể tự mình thử điều này bằng cách viết một chương trình C nhỏ phân bổ một mảng tĩnh lớn gồm các mục 10k, 1m, 10m, 100m, 1G hoặc 10G. Đối với nhiều trình biên dịch, kích thước nhị phân sẽ tiếp tục tăng tuyến tính với kích thước của mảng và vượt qua một điểm nhất định,

Đăng ký bộ nhớ

Lớp bộ nhớ cuối cùng là các biến 'đăng ký'. Như mong đợi, các biến thanh ghi nên được cấp phát trên thanh ghi của CPU, nhưng quyết định thực sự được để cho trình biên dịch. Bạn không thể biến một biến đăng ký thành một tham chiếu bằng cách sử dụng address-of.

register int meaning = 42;
printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */

Hầu hết các trình biên dịch hiện đại thông minh hơn bạn trong việc chọn biến nào nên được đưa vào thanh ghi :)

Người giới thiệu:


3
Lưu ý: int * a = malloc(sizeof(*a));Thay vào đó, tôi đề xuất , để tránh lặp lại loại a. Điều này làm cho mọi thứ dễ dàng hơn nhiều nếu loại athay đổi.
Shahbaz

1
Về cơ bản, nó được gọi là heap nhưng nó không liên quan gì đến cấu trúc dữ liệu heap. Heap trong trường hợp này có nghĩa là một nơi lộn xộn
động

2
"Cấp phát bộ nhớ tĩnh ... Được cấp phát tại thời điểm biên dịch" Bạn có nghĩa là kích thước cấp phát được xác định tại thời điểm biên dịch? Không phải việc đặt bộ nhớ sang một bên sẽ chỉ xảy ra trong thời gian chạy?
lf215

2

Cấp phát bộ nhớ tĩnh: Trình biên dịch phân bổ không gian bộ nhớ cần thiết cho một biến đã khai báo. Bằng cách sử dụng địa chỉ của toán tử, địa chỉ dành riêng sẽ được lấy và địa chỉ này có thể được gán cho một biến con trỏ. cách gán giá trị con trỏ cho một biến con trỏ được gọi là cấp phát bộ nhớ tĩnh. bộ nhớ được gán trong thời gian biên dịch.

Cấp phát bộ nhớ động: Nó sử dụng các hàm như malloc () hoặc calloc () để lấy bộ nhớ động. phân bổ.memory được xác định trong thời gian chạy.


2

Phân bổ bộ nhớ tĩnh:

  • Các biến được phân bổ vĩnh viễn
  • Việc phân bổ được thực hiện trước khi thực hiện chương trình
  • Nó sử dụng cấu trúc dữ liệu được gọi là ngăn xếp để thực hiện phân bổ tĩnh
  • Kém hiệu quả
  • Không có khả năng tái sử dụng bộ nhớ

Phân bổ bộ nhớ động:

  • Biến được phân bổ chỉ nếu đơn vị chương trình được kích hoạt
  • Phân bổ được thực hiện trong quá trình thực hiện chương trình
  • Nó sử dụng cấu trúc dữ liệu được gọi là heap để triển khai phân bổ động
  • Hiệu quả hơn
  • khả năng tái sử dụng bộ nhớ . Bộ nhớ có thể được giải phóng khi không cần thiết

1
"Phân bổ bộ nhớ tĩnh [...] Nó sử dụng cấu trúc dữ liệu được gọi là ngăn xếp để thực hiện phân bổ tĩnh" Không , điều đó không chính xác và gây hiểu lầm. vui lòng xem bài đăng của tôi để biết sự khác biệt giữa phân bổ tự động và tĩnh. Bộ nhớ tĩnh có thể sử dụng ngăn xếp. Điều này phụ thuộc nhiều vào việc triển khai và nhiều chiến lược có thể được sử dụng cho cùng một cách triển khai. Tôi cũng không rõ ý bạn là "Kém hiệu quả hơn". @Trieu Toan, bạn đã thay đổi ý nghĩa của câu trả lời này bằng một bản sửa sai.
brice

1

Sự khác biệt giữa PHÂN PHỐI BỘ NHỚ TRẠNG THÁIPHÂN PHỐI BỘ NHỚ ĐỘNG

Bộ nhớ được cấp phát trước khi bắt đầu thực thi chương trình (Trong quá trình biên dịch).
Bộ nhớ được cấp phát trong quá trình thực hiện chương trình.

Không có hành động cấp phát bộ nhớ hoặc phân bổ bộ nhớ nào được thực hiện trong khi Thực thi.
Các ràng buộc bộ nhớ được thiết lập và phá hủy trong quá trình thực thi.

Các biến vẫn được phân bổ vĩnh viễn.
Chỉ được phân bổ khi đơn vị chương trình đang hoạt động.

Được triển khai bằng cách sử dụng ngăn xếp và đống.
Được triển khai bằng cách sử dụng các phân đoạn dữ liệu.

Con trỏ là cần thiết để truy cập các biến.
Không cần con trỏ được phân bổ động.

Thực thi nhanh hơn Dynamic.
Thực hiện chậm hơn tĩnh.

Cần thêm dung lượng bộ nhớ.
Yêu cầu ít dung lượng bộ nhớ hơn.


1
cấp phát bộ nhớ tĩnh được cấp phát trên Stack trong khi cấp phát bộ nhớ động được cấp phát trên Heap
Usman Kurd

@UsmanKurd Điều đó thường không chính xác về bộ nhớ tĩnh. Hãy xem câu trả lời của tôi.
brice

0

Cấp phát bộ nhớ tĩnh được cấp phát bộ nhớ trước khi chương trình pf thực thi trong thời gian biên dịch. Vị trí bộ nhớ động là bộ nhớ được định vị trong quá trình thực thi chương trình tại thời điểm chạy.


-1

Cấp phát bộ nhớ tĩnh. Bộ nhớ được cấp phát sẽ nằm trong ngăn xếp.

int a[10];

Cấp phát bộ nhớ động. Bộ nhớ được cấp phát sẽ ở trong heap.

int *a = malloc(sizeof(int) * 10);

và cái sau sẽ miễn phí d vì không có Bộ thu gom rác (GC) trong C.

free(a);
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.