Ngoài các câu trả lời khác, tôi muốn thêm rằng khi khắc RAM giữa không gian ngăn xếp và vùng heap, bạn cũng cần xem xét không gian cho dữ liệu không cố định (ví dụ: toàn cầu tệp, thống kê chức năng và toàn chương trình toàn cầu từ góc độ C, và có thể là những người khác cho C ++).
Cách phân bổ stack / heap hoạt động
Điều đáng chú ý là tệp lắp ráp khởi động là một cách để xác định vùng; chuỗi công cụ (cả môi trường xây dựng và môi trường thời gian chạy của bạn) chủ yếu quan tâm đến các biểu tượng xác định bắt đầu stackspace (được sử dụng để lưu trữ con trỏ ngăn xếp ban đầu trong Bảng Vector) và bắt đầu và kết thúc không gian heap (được sử dụng bởi động cấp phát bộ nhớ, thường được cung cấp bởi libc của bạn)
Trong ví dụ của OP, chỉ có 2 biểu tượng được xác định, kích thước ngăn xếp ở 1kiB và kích thước heap ở 0B. Các giá trị này được sử dụng ở nơi khác để thực sự tạo ra không gian ngăn xếp và đống
Trong ví dụ @Gilles, các kích thước được xác định và sử dụng trong tệp lắp ráp để đặt không gian ngăn xếp bắt đầu ở bất cứ đâu và kéo dài kích thước, được xác định bởi biểu tượng Stack_Mem và đặt nhãn __initial_sp ở cuối. Tương tự như vậy đối với vùng heap, trong đó khoảng trắng là ký hiệu Heap_Mem (kích thước 0,5kiB), nhưng có nhãn ở đầu và cuối (__heap_base và __heap_limit).
Chúng được xử lý bởi trình liên kết, sẽ không phân bổ bất cứ thứ gì trong không gian ngăn xếp và không gian heap vì bộ nhớ đó bị chiếm dụng (bởi các biểu tượng Stack_Mem và Heap_Mem), nhưng nó có thể đặt những ký ức đó và tất cả các quả cầu bất cứ nơi nào nó cần. Các nhãn cuối cùng là các ký hiệu không có độ dài tại các địa chỉ đã cho. __Initial_sp được sử dụng trực tiếp cho bảng vectơ tại thời điểm liên kết và __heap_base và __heap_limit bởi mã thời gian chạy của bạn. Địa chỉ thực tế của các ký hiệu được chỉ định bởi trình liên kết dựa trên vị trí đặt biểu tượng.
Như tôi đã nói ở trên, những biểu tượng này thực sự không phải đến từ tệp startup.s. Chúng có thể đến từ cấu hình trình liên kết của bạn (tệp Scatter Load trong Keil, linkercript trong GNU) và trong những thứ bạn có thể kiểm soát chi tiết hơn đối với vị trí. Ví dụ: bạn có thể buộc ngăn xếp ở đầu hoặc cuối RAM hoặc giữ các quả cầu của bạn cách xa đống hoặc bất cứ thứ gì bạn muốn. Bạn thậm chí có thể chỉ định rằng HEAP hoặc STACK chỉ chiếm bất kỳ RAM nào còn sót lại sau khi đặt toàn cầu. LƯU Ý mặc dù bạn phải cẩn thận rằng việc thêm nhiều biến tĩnh mà bộ nhớ khác của bạn sẽ giảm.
Tuy nhiên, mỗi chuỗi công cụ là khác nhau và cách viết tệp cấu hình và những ký hiệu mà bộ cấp phát bộ nhớ động của bạn sẽ sử dụng sẽ phải đến từ tài liệu về môi trường cụ thể của bạn.
Kích thước ngăn xếp
Về cách xác định kích thước ngăn xếp, nhiều bộ công cụ có thể cung cấp cho bạn độ sâu ngăn xếp tối đa bằng cách phân tích các cây gọi hàm của chương trình của bạn, NẾU bạn không sử dụng đệ quy hoặc con trỏ hàm. Nếu bạn sử dụng chúng, hãy ước tính kích thước ngăn xếp và điền trước nó với các giá trị chính (có lẽ thông qua chức năng nhập trước chính) và sau đó kiểm tra sau khi chương trình của bạn chạy trong một thời gian có độ sâu tối đa (đó là nơi có giá trị chính kết thúc). Nếu bạn đã thực hiện đầy đủ chương trình của mình đến giới hạn của nó, bạn sẽ biết khá chính xác liệu bạn có thể thu nhỏ ngăn xếp hay không, nếu chương trình của bạn gặp sự cố hoặc không còn giá trị chính, bạn cần tăng ngăn xếp và thử lại.
Kích thước đống
Xác định kích thước heap phụ thuộc vào ứng dụng nhiều hơn một chút. Nếu bạn chỉ thực hiện phân bổ động trong khi khởi động, bạn chỉ có thể thêm không gian cần thiết trong mã khởi động của mình (cộng với một số chi phí để quản lý bộ nhớ). Nếu bạn có quyền truy cập vào nguồn của trình quản lý bộ nhớ, bạn có thể biết chính xác chi phí là gì và thậm chí có thể viết mã để chuyển bộ nhớ để cung cấp cho bạn thông tin sử dụng. Đối với các ứng dụng cần bộ nhớ thời gian chạy động (ví dụ: phân bổ bộ đệm cho các khung ethernet bên trong), điều tốt nhất tôi có thể đề xuất là cẩn thận trau dồi ngăn xếp của bạn và cung cấp cho Heap mọi thứ còn sót lại sau stack và statics.
Lưu ý cuối cùng (RTOS)
Câu hỏi của OP đã được gắn thẻ cho kim loại trần, nhưng tôi muốn thêm một ghi chú cho RTOSes. Thông thường (luôn luôn?) Mỗi tác vụ / quy trình / luồng (tôi sẽ chỉ viết tác vụ ở đây cho đơn giản) sẽ được chỉ định kích thước ngăn xếp khi tác vụ được tạo, ngoài ngăn xếp tác vụ, có thể sẽ có một hệ điều hành nhỏ ngăn xếp (được sử dụng cho các ngắt và như vậy)
Các cấu trúc kế toán nhiệm vụ và các ngăn xếp phải được phân bổ từ một nơi nào đó và điều này thường sẽ từ không gian heap tổng thể của ứng dụng của bạn. Trong các trường hợp này, kích thước ngăn xếp ban đầu của bạn thường không thành vấn đề, bởi vì HĐH sẽ chỉ sử dụng nó trong quá trình khởi tạo. Tôi đã thấy, ví dụ, chỉ định TẤT CẢ không gian còn lại trong khi liên kết được phân bổ cho HEAP và đặt con trỏ ngăn xếp ban đầu ở cuối heap để phát triển thành heap, biết rằng HĐH sẽ phân bổ bắt đầu từ đầu heap và sẽ phân bổ ngăn xếp hệ điều hành ngay trước khi từ bỏ ngăn xếp ban đầu. Sau đó, tất cả không gian được sử dụng để phân bổ ngăn xếp nhiệm vụ và bộ nhớ được phân bổ động khác.