🌱 RTOS 05. Quản lý bộ nhớ trong RTOS - Heap Memory Management

🌱 RTOS 05. Quản lý bộ nhớ trong RTOS - Heap Memory Management

    Ở post trước chúng ta đã cùng tìm hiểu về phần cứng sử dụng để xây dựng một hệ điều hành RTOS. Một hệ điều hành RTOS trên vi điều khiển bao gồm các task được phân bổ bộ nhớ trên vùng nhớ khác nhau, vì vậy việc cấp phát và quản lý bộ nhớ này là vô cùng quan trọng.

💛 Bài viết này là phần tìm hiểu của bạn Đặng Văn Sơn, người anh em cùng team FPT. Mình xin gửi lời cảm ơn của anh em đọc được bài viết này đến bạn.

    Các hệ điều hành RTOS thông thường sử dụng cấp phát động (vùng nhớ Heap) bởi vì các task được tạo trong lúc runtime nên cần cấp phát động. Một số cách làm có thể triển khai bộ nhớ tĩnh cho các task khi cố định các task từ lúc compile.

    Các nội dung chính

    1. Ý tưởng chung về quản lý bộ nhớ Heap
    2. Ví dụ cách quản lý Heap của freeRTOS

    Ý tưởng chung về quản lý bộ nhớ Heap

        Về cơ bản, trong RTOS cần quản lý RTOS cho các yếu tố: các Tasks, cho các cơ chế Semaphore, Queue, Mutex, và việc cấp phát động (Dynamic memory allocation). Cách thức cấp phát bộ nhớ sẽ ảnh hưởng lớn đến hiệu suất, độ tin cậy, và tính quyết định (determinism) của toàn hệ thống.

        Như đã nói ở trên thì có hai phương án để cấp phát bộ nhớ cho các Task.

    • Cấp phát tĩnh: Bộ nhớ được cấp phát trước tại thời điểm biên dịch. Từ đó kích thước sẽ cố định và không phụ thuộc vào runtime, không gây phân mảnh bộ nhớ.Tuy nhiên là tính linh hoạt kém, nếu dùng ít quá so với cấp phát thì lãng phí bộ nhớ, nếu dùng nhiều quá hơn so với cấp phát thì không được.
    • Cấp phát động: Bộ nhớ được cấp phát trong runtime từ heap. Ưu điểm là linh hoạt, dễ dàng tạo và free bộ nhớ khi cần thiết.

        Nếu các thành phần trong RTOS được cấp phát động thì đôi khi có thể sử dụng các hàm malloc() và free() của thư viện C chuẩn cho mục đích này, nhưng ...

    • Các hàm này không phải lúc nào cũng có sẵn trên các hệ thống nhúng,
    • Không đảm bảo Thread-Safe,
    • Không cố định về thời gian thực thi hàm,
        ... do đó, thường thì cần phải triển khai các hàm phân bổ bộ nhớ thay thế. Chẳng hạn như trong freeRTOS sử dụng các hàm pvPortMalloc() và vPortFree() thay vì malloc() và free() trong thư viện C chuẩn. Các hàm này tuân thủ các quy tắc liên quan đến multitasking để tránh phân mảnh bộ nhớ hoặc xung đột giữa các task, đảm bảo Thread-Safe và có cơ chế Hook để thông báo và xử lý lỗi.

        Dưới đây là các cách quản lý bộ nhớ Heap của freeRTOS.

    Ví dụ cách quản lý Heap của freeRTOS

        Có 5 cách cơ bản để cấp phát bộ nhớ trong freeRTOS

        👉 Heap_1

        Đây là cách cấp phát cơ bản nhất và không cho phép giải phóng bộ nhớ.

        Cách này rất đơn giản là cấp một mảng cố định trên Heap để đặt các Task vào. Mỗi task bao gồm TCB + Stack như đã nói ở bài trước.
    • Ưu điểm của phương pháp triên khai này là đơn giản, dễ sử dụng, chỉ cần cấp phát mảng tĩnh cố định trên Heap.
    • Nhược điểm của nó là không giải phóng bộ nhớ được, nên chỉ dùng với những ứng dụng mà chúng ta không cần xóa các Task, Semaphore, Mutex, ... 

        👉 Heap_2

        Cho phép giải phóng bộ nhớ, nhưng không đặt các vùng Task cạnh nhau. 

        Cách cấp phát này giống như cách cấp phát ở Heap_1 là dùng một mảng để chứa các Task, nhưng nó cho phép giải phóng các vùng nhớ của các Task.
        Chẳng hạn trong ví dụ trên, Task thứ 2 (ở giữa) được free(), nhưng Task trên cùng sẽ không được sắp xếp cạnh Task dưới cùng mà vẫn giữ nguyên vị trí của nó.
        Cách này có thể gây ra phân mảng bộ nhớ, nếu như không biết trước được kích thước của các Task sử dụng.

        👉 Heap_3

        Cách này sử dùng các hàm theo thư viện chuẩn C, đó là malloc() và free() để cấp phát và giải phóng bộ nhớ. 

        Để triển khai được Heap_3, dùng thư viện chuẩn trong C thì vi điều khiển cần được xác định một vùng nhớ heap bằng linker (Vì trong vi điều khiển chỉ phân biệt FLASH, RAM, không phân biệt rõ ràng đâu là Heap, đâu là Stack, nên cần quy định đâu là Heap trong file Linker Script).

        👉 Heap_4

        Giống như Heap_2 tuy nhiên cho phép sử dụng lại các vùng Free Space.

        Vùng nhớ Task sau khi free() sẽ là vùng free space. Vùng nhớ này ở Heap_2 sẽ không được sử dụng, có thể gây ra phân mảng bộ nhớ. Khác với Heap_2, Heap_4 cho phép sử dụng vùng nhớ này.

        👉 Heap_5

        Không giống như Heap_4, Heap_5 không bị giới hạn trong việc cấp phát bộ nhớ từ một mảng được khai báo tĩnh duy nhất; Heap_5 có thể cấp phát bộ nhớ từ nhiều không gian bộ nhớ riêng biệt.

        Điều này khá hữu ích khi RAM được phân cách thành nhiều vùng như hình trên.

        👉 Các cách phân bổ bộ nhớ trên Heap khác quan trọng khi thiết kế RTOS, tùy vào ứng dụng cụ thể cũng như tài nguyên của hệ thống, chúng ta sẽ có những cách thiết kế khác nhau.

    >>>= Follow ngay =<<<

    Để theo dõi những bài học miễn phí mới nhất nhé 😊

    Chúc các bạn học tập tốt 😊

                          

    Nguyễn Văn Nghĩa

    Mình là một người thích học hỏi và chia sẻ các kiến thức về Nhúng IOT.

    Đăng nhận xét

    Mới hơn Cũ hơn