2008-10-07 45 views
20

Tôi có một ứng dụng nhúng, đơn luồng được phân bổ và phân bổ rất nhiều và nhiều khối nhỏ (32-64b). Kịch bản hoàn hảo cho bộ đệm dựa trên bộ đệm. Và mặc dù tôi có thể TRY để viết một trong những nó có thể sẽ là một sự lãng phí thời gian, và cũng không được kiểm tra và điều chỉnh như một số giải pháp đó đã được trên đường phía trước.Trình phân bổ bộ nhớ C tốt cho hệ thống nhúng là gì?

Vì vậy, trình phân bổ tốt nhất mà tôi có thể sử dụng cho trường hợp này là gì? Lưu ý: Tôi đang sử dụng một Lua Virtual Machine trong hệ thống (là thủ phạm của 80 +% phân bổ), vì vậy tôi không thể trivially refactor mã của tôi để sử dụng phân bổ stack để tăng hiệu suất phân bổ.

Trả lời

7

Tôi đã thực hiện một số nghiên cứu về chủ đề này gần đây, vì chúng tôi gặp sự cố với phân mảnh bộ nhớ. Cuối cùng, chúng tôi quyết định ở lại với việc thực hiện GNU libc, và thêm một số vùng nhớ cấp ứng dụng khi cần thiết. Có những người phân bổ khác có hành vi phân mảnh tốt hơn, nhưng chúng tôi không đủ thoải mái với họ thay thế malloc trên toàn cầu. GNU có lợi ích của một lịch sử lâu dài đằng sau nó.

Trong trường hợp của bạn, có vẻ như hợp lý; giả sử bạn không thể sửa chữa VM, những phân bổ nhỏ bé này rất lãng phí. Tôi không biết toàn bộ môi trường của bạn là gì, nhưng bạn có thể xem xét gói các cuộc gọi đến malloc/realloc/miễn phí trên máy ảo để bạn có thể truyền nó cho một trình xử lý được thiết kế cho các hồ nhỏ.

+0

Được sử dụng Loki cho mục đích này, tất cả đã hoạt động tốt và mất rất ít thời gian –

+0

Chris, bạn có sẵn sàng chia sẻ mã cho phiên bản sửa đổi của glibc malloc với các bộ nhớ không? –

8

Trong một dự án trước đây trong C tôi đã làm việc, chúng tôi đã đi trên con đường thực hiện các thói quen quản lý bộ nhớ riêng của chúng tôi cho một thư viện chạy trên một loạt các nền tảng bao gồm các hệ thống nhúng. Thư viện cũng phân bổ và giải phóng một số lượng lớn các bộ đệm nhỏ. Nó chạy tương đối tốt và không mất một số lượng lớn mã để thực hiện. Tôi có thể cung cấp cho bạn một chút thông tin cơ bản về việc triển khai đó trong trường hợp bạn muốn tự mình phát triển điều gì đó.

Triển khai cơ bản bao gồm tập hợp các thói quen quản lý bộ đệm có kích thước đã đặt. Các thường trình được sử dụng như các trình bao bọc xung quanh malloc() và miễn phí(). Chúng tôi đã sử dụng các thường trình này để quản lý việc phân bổ các cấu trúc mà chúng tôi thường xuyên sử dụng và cũng để quản lý bộ đệm chung của các kích thước đã đặt. Một cấu trúc được sử dụng để mô tả từng loại bộ đệm được quản lý. Khi một bộ đệm của một kiểu cụ thể được phân bổ, chúng ta sẽ malloc() bộ nhớ trong các khối (nếu một danh sách các bộ đệm tự do trống). IE, nếu chúng ta quản lý 10 bộ đệm byte, chúng ta có thể tạo một đơn vị malloc() chứa khoảng trống cho 100 bộ đệm này để giảm phân mảnh và số lượng mallocs cơ bản cần thiết.

Ở mặt trước của mỗi bộ đệm sẽ là một con trỏ sẽ được sử dụng để chuỗi các bộ đệm trong danh sách miễn phí. Khi 100 bộ đệm được cấp phát, mỗi bộ đệm sẽ được xích lại với nhau trong danh sách miễn phí. Khi bộ đệm được sử dụng, con trỏ sẽ được đặt thành null. Chúng tôi cũng duy trì một danh sách các "khối" của bộ đệm, để chúng tôi có thể làm một đơn giản dọn dẹp bằng cách gọi miễn phí() trên mỗi bộ đệm malloc'd thực tế.

Để quản lý kích thước bộ đệm động, chúng tôi cũng đã thêm biến size_t ở đầu mỗi bộ đệm cho biết kích thước của bộ đệm. Điều này sau đó được sử dụng để xác định khối đệm để đưa bộ đệm trở lại khi nó được giải phóng. Chúng tôi đã thay thế thói quen cho malloc() và miễn phí() đã làm số học con trỏ để có được kích thước bộ đệm và sau đó để đưa bộ đệm vào danh sách miễn phí. Chúng tôi cũng đã có giới hạn về số lượng bộ đệm chúng tôi quản lý. Bộ đệm lớn hơn giới hạn này chỉ đơn giản là malloc'd và được chuyển cho người dùng. Đối với các cấu trúc mà chúng tôi quản lý, chúng tôi đã tạo các trình bao bọc cho việc phân bổ và giải phóng các cấu trúc cụ thể.

Cuối cùng, chúng tôi cũng đã phát triển hệ thống để bao gồm thu gom rác khi người dùng yêu cầu xóa bộ nhớ không sử dụng. Vì chúng tôi đã kiểm soát toàn bộ hệ thống, có nhiều tối ưu hóa khác nhau mà chúng tôi có thể thực hiện theo thời gian để tăng hiệu suất của hệ thống. Như tôi đã đề cập, nó đã hoạt động khá tốt.

6

Mặc dù đã đến lúc tôi hỏi điều này, giải pháp cuối cùng của tôi là sử dụng SmallObjectAllocator của LoKi, nó hoạt động rất tốt. Đã thoát khỏi tất cả các cuộc gọi hệ điều hành và cải thiện hiệu suất của động cơ Lua của tôi cho các thiết bị nhúng. Rất đẹp và đơn giản, và chỉ khoảng 5 phút giá trị công việc!

3

Tôi cũng muốn thêm vào điều này mặc dù đây là một chuỗi cũ. Trong một ứng dụng nhúng nếu bạn có thể phân tích mức sử dụng bộ nhớ của bạn cho ứng dụng của bạn và đưa ra một số lượng cấp phát bộ nhớ tối đa cho các kích thước khác nhau, thường là loại cấp phát nhanh nhất là một bộ nhớ sử dụng bộ nhớ. Trong các ứng dụng nhúng của chúng tôi, chúng tôi có thể xác định tất cả các kích thước phân bổ sẽ cần thiết trong thời gian chạy. Nếu bạn có thể làm điều này bạn hoàn toàn có thể loại bỏ phân mảnh đống và có phân bổ rất nhanh. Hầu hết các triển khai này có một hồ bơi tràn sẽ làm một malloc thường xuyên cho các trường hợp đặc biệt mà hy vọng sẽ được xa và rất ít giữa nếu bạn đã làm phân tích của bạn đúng.

+1

điểm rất tốt! Tôi quên mất điều này, nhưng đó chính xác là những gì tôi đã làm khi tôi đang lập trình trên GameBoy –

2

Tôi đã sử dụng hệ thống 'bạn thân nhị phân' để có hiệu quả tốt trong vxworks. Về cơ bản, bạn chia nhỏ khối của mình bằng cách cắt khối thành một nửa để có được sức mạnh nhỏ nhất của hai khối có kích thước để giữ yêu cầu của bạn, và khi các khối được giải phóng, bạn có thể tạo một cây để kết hợp các khối lại với nhau để giảm thiểu sự phân mảnh. Tìm kiếm trên google sẽ bật lên tất cả thông tin bạn cần.

7

tôi là một chút muộn để đảng, nhưng tôi chỉ muốn chia sẻ cấp phát bộ nhớ rất hiệu quả cho các hệ thống nhúng Tôi vừa mới tìm thấy và thử nghiệm: https://github.com/dimonomid/umm_malloc

Đây là một thư viện quản lý bộ nhớ được thiết kế đặc biệt để làm việc với ARM7, cá nhân tôi sử dụng nó trên thiết bị PIC32, nhưng nó sẽ hoạt động trên bất kỳ thiết bị 16 và 8 bit nào (tôi có kế hoạch thử nghiệm trên PIC24 16 bit, nhưng tôi chưa thử nghiệm)

Tôi đã bị đánh đập nghiêm trọng bởi phân mảnh với trình phân bổ mặc định: dự án của tôi thường phân bổ các khối có kích thước khác nhau, từ vài byte đến vài trăm byte và đôi khi tôi gặp lỗi 'hết bộ nhớ'. Thiết bị PIC32 của tôi có tổng cộng 32K RAM và 8192 byte được sử dụng cho heap. Tại thời điểm cụ thể có hơn 5K bộ nhớ trống, nhưng bộ cấp phát mặc định có khối bộ nhớ không phân mảnh tối đa chỉ khoảng 700 byte, do phân mảnh. Điều này là quá xấu, vì vậy tôi quyết định tìm giải pháp hiệu quả hơn.

Tôi đã biết một số trình phân bổ, nhưng tất cả chúng có một số hạn chế (chẳng hạn như kích thước khối phải là một hoặc 2, và bắt đầu không từ 2 nhưng từ, nói, 128 byte), hoặc chỉ là lỗi. Mỗi lần trước, tôi phải chuyển về trình phân bổ mặc định.

Nhưng lần này, tôi thật may mắn: Tôi đã tìm thấy cái này: http://hempeldesigngroup.com/embedded/stories/memorymanager/

Khi tôi đã cố gắng cấp phát bộ nhớ này, chính xác tình hình tương tự với 5K bộ nhớ miễn phí, nó có hơn 3800 byte khối ! Nó không thể tin được với tôi (so với 700 byte), và tôi đã thực hiện thử nghiệm khó khăn: thiết bị hoạt động mạnh hơn 30 giờ. Không có rò rỉ bộ nhớ, mọi thứ hoạt động vì nó hoạt động. Tôi cũng tìm thấy phân bổ này trong kho lưu trữ FreeRTOS: http://svnmios.midibox.org/listing.php?repname=svn.mios32&path=%2Ftrunk%2FFreeRTOS%2FSource%2Fportable%2FMemMang%2F&rev=1041&peg=1041#, và thực tế này là một bằng chứng bổ sung về sự ổn định của umm_malloc. Vì vậy, tôi hoàn toàn chuyển sang umm_malloc, và tôi khá hài lòng với nó.

Tôi chỉ phải thay đổi một chút: cấu hình hơi lỗi khi macro UMM_TEST_MAIN không được xác định, vì vậy, tôi đã tạo kho lưu trữ github (liên kết nằm ở đầu bài đăng này). Bây giờ, cấu hình phụ thuộc người dùng được lưu trữ trong tập tin riêng biệt umm_malloc_cfg.h

Tôi chưa hiểu sâu về các thuật toán được áp dụng trong trình phân bổ này, nhưng nó có giải thích rất chi tiết về thuật toán, vì vậy bất kỳ ai quan tâm đều có thể xem ở đầu tệp umm_malloc.c. Ít nhất, cách tiếp cận "binning" sẽ mang lại lợi ích to lớn trong phân mảnh ít hơn: http://g.oswego.edu/dl/html/malloc.html

Tôi tin rằng bất cứ ai cần phân bổ bộ nhớ hiệu quả cho vi điều khiển, ít nhất nên thử cái này.

+2

đây là câu trả lời hay nhất ở đây. Cảm ơn các liên kết! Nếu bạn quan tâm, hãy kiểm tra quản lý bộ nhớ của tôi cũng: https://github.com/cloudformdesign/tinymem Tôi đã thiết kế nó để xử lý phân mảnh :) – vitiral

-1

Tôi đang viết bộ cấp phát bộ nhớ C được gọi là tinymem nhằm mục đích có khả năng chống phân mảnh vùng nhớ và sử dụng lại bộ nhớ. Check it out:

https://github.com/vitiral/tinymem

Lưu ý: Dự án này đã hết hiệu lực để làm việc về việc thực hiện gỉ:

https://github.com/vitiral/defrag-rs

Ngoài ra, tôi đã không nghe nói về umm_malloc trước. Thật không may, nó không có vẻ để có thể đối phó với phân mảnh, nhưng nó chắc chắn có vẻ hữu ích. Tôi sẽ cho người kiểm tra việc đó.

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