Nói ngắn gọn
Một ngăn xếp được sử dụng để cấp phát bộ nhớ tĩnh và một đống cho phân bổ bộ nhớ động, cả hai được lưu trữ trong RAM của máy tính.
Chi tiết
Chồng
Ngăn xếp là cấu trúc dữ liệu "LIFO" (cuối cùng vào trước ra trước), được CPU quản lý và tối ưu hóa khá chặt chẽ. Mỗi khi một hàm khai báo một biến mới, nó sẽ được "đẩy" lên ngăn xếp. Sau đó, mỗi khi một hàm thoát ra, tất cả các biến được đẩy lên ngăn xếp bởi hàm đó, sẽ được giải phóng (nghĩa là chúng bị xóa). Khi một biến ngăn xếp được giải phóng, vùng bộ nhớ đó sẽ khả dụng cho các biến ngăn xếp khác.
Ưu điểm của việc sử dụng ngăn xếp để lưu trữ các biến là bộ nhớ được quản lý cho bạn. Bạn không phải phân bổ bộ nhớ bằng tay hoặc giải phóng nó một khi bạn không cần nó nữa. Hơn thế nữa, vì CPU tổ chức bộ nhớ ngăn xếp rất hiệu quả, việc đọc và ghi vào các biến ngăn xếp rất nhanh.
Nhiều hơn có thể được tìm thấy ở đây .
Heap
Vùng heap là vùng bộ nhớ máy tính của bạn không được quản lý tự động cho bạn và không được CPU quản lý chặt chẽ. Đây là vùng bộ nhớ nổi tự do hơn (và lớn hơn). Để phân bổ bộ nhớ trên heap, bạn phải sử dụng malloc () hoặc calloc (), là các hàm C tích hợp. Khi bạn đã phân bổ bộ nhớ trên heap, bạn có trách nhiệm sử dụng free () để giải phóng bộ nhớ đó một khi bạn không cần nó nữa.
Nếu bạn không làm điều này, chương trình của bạn sẽ có cái được gọi là rò rỉ bộ nhớ. Đó là, bộ nhớ trên heap vẫn sẽ được đặt sang một bên (và sẽ không có sẵn cho các quy trình khác). Như chúng ta sẽ thấy trong phần gỡ lỗi, có một công cụ có tên Valgrind có thể giúp bạn phát hiện rò rỉ bộ nhớ.
Không giống như ngăn xếp, heap không có giới hạn kích thước đối với kích thước thay đổi (ngoài các giới hạn vật lý rõ ràng của máy tính của bạn). Bộ nhớ heap hơi chậm để đọc và ghi vào, bởi vì người ta phải sử dụng các con trỏ để truy cập bộ nhớ trên heap. Chúng tôi sẽ nói về con trỏ trong thời gian ngắn.
Không giống như ngăn xếp, các biến được tạo trên heap có thể được truy cập bởi bất kỳ hàm nào, bất cứ nơi nào trong chương trình của bạn. Biến Heap về cơ bản là toàn cầu trong phạm vi.
Nhiều hơn có thể được tìm thấy ở đây .
Các biến được phân bổ trên ngăn xếp được lưu trữ trực tiếp vào bộ nhớ và truy cập vào bộ nhớ này rất nhanh và việc phân bổ của nó được xử lý khi chương trình được biên dịch. Khi một hàm hoặc một phương thức gọi một hàm khác lần lượt gọi một hàm khác, v.v., việc thực thi tất cả các hàm đó vẫn bị treo cho đến khi hàm cuối cùng trả về giá trị của nó. Ngăn xếp luôn được bảo lưu theo thứ tự LIFO, khối dành riêng gần đây nhất luôn là khối tiếp theo được giải phóng. Điều này làm cho việc theo dõi ngăn xếp thực sự đơn giản, giải phóng một khối khỏi ngăn xếp không gì khác hơn là điều chỉnh một con trỏ.
Các biến được phân bổ trên vùng heap có bộ nhớ được cấp phát trong thời gian chạy và truy cập bộ nhớ này chậm hơn một chút, nhưng kích thước vùng heap chỉ bị giới hạn bởi kích thước của bộ nhớ ảo. Các yếu tố của heap không có sự phụ thuộc lẫn nhau và luôn có thể được truy cập ngẫu nhiên bất cứ lúc nào. Bạn có thể phân bổ một khối bất cứ lúc nào và giải phóng nó bất cứ lúc nào. Điều này làm cho nó phức tạp hơn nhiều để theo dõi phần nào của heap được phân bổ hoặc miễn phí tại bất kỳ thời điểm nào.
Bạn có thể sử dụng ngăn xếp nếu bạn biết chính xác lượng dữ liệu bạn cần phân bổ trước khi biên dịch thời gian và nó không quá lớn. Bạn có thể sử dụng heap nếu bạn không biết chính xác mình sẽ cần bao nhiêu dữ liệu khi chạy hoặc nếu bạn cần phân bổ nhiều dữ liệu.
Trong một tình huống đa luồng, mỗi luồng sẽ có ngăn xếp hoàn toàn độc lập của riêng mình, nhưng chúng sẽ chia sẻ heap. Ngăn xếp là luồng cụ thể và heap là ứng dụng cụ thể. Ngăn xếp là quan trọng để xem xét trong xử lý ngoại lệ và thực thi luồng.
Mỗi luồng có một ngăn xếp, trong khi thông thường chỉ có một đống cho ứng dụng (mặc dù không có nhiều heap cho các loại phân bổ khác nhau).
Trong thời gian chạy, nếu ứng dụng cần nhiều heap, nó có thể phân bổ bộ nhớ từ bộ nhớ trống và nếu ngăn xếp cần bộ nhớ, nó có thể phân bổ bộ nhớ từ bộ nhớ cấp phát bộ nhớ cho ứng dụng.
Thậm chí, chi tiết hơn được đưa ra ở đây và ở đây .
Bây giờ đến câu trả lời câu hỏi của bạn .
Ở mức độ nào chúng được điều khiển bởi hệ điều hành hoặc thời gian chạy ngôn ngữ?
HĐH phân bổ ngăn xếp cho từng luồng cấp hệ thống khi luồng được tạo. Thông thường, HĐH được gọi bởi bộ thực thi ngôn ngữ để phân bổ heap cho ứng dụng.
Nhiều hơn có thể được tìm thấy ở đây .
Phạm vi của họ là gì?
Đã được đưa ra trong đầu.
"Bạn có thể sử dụng ngăn xếp nếu bạn biết chính xác lượng dữ liệu bạn cần phân bổ trước thời gian biên dịch và nó không quá lớn. Bạn có thể sử dụng heap nếu bạn không biết chính xác mình sẽ cần bao nhiêu dữ liệu khi chạy hoặc nếu bạn cần phân bổ nhiều dữ liệu. "
Nhiều hơn có thể được tìm thấy ở đây .
Điều gì quyết định kích thước của mỗi người trong số họ?
Kích thước của ngăn xếp được thiết lập bởi hệ điều hành khi một luồng được tạo. Kích thước của heap được đặt khi khởi động ứng dụng, nhưng nó có thể tăng lên khi cần không gian (bộ cấp phát yêu cầu thêm bộ nhớ từ hệ điều hành).
Điều gì làm cho một người nhanh hơn?
Phân bổ ngăn xếp nhanh hơn nhiều vì tất cả những gì nó thực sự làm là di chuyển con trỏ ngăn xếp. Sử dụng nhóm bộ nhớ, bạn có thể có được hiệu năng tương đương từ phân bổ heap, nhưng điều đó đi kèm với một sự phức tạp được thêm vào một chút và đau đầu của chính nó.
Ngoài ra, stack vs heap không chỉ là một xem xét hiệu suất; nó cũng cho bạn biết rất nhiều về tuổi thọ dự kiến của các vật thể.
Thông tin chi tiết có thể được tìm thấy từ đây .