Penggunaan malloc di PIC

10

Bagaimana saya bisa menggunakan malloc()dan free()fungsi dalam PIC? Saya sudah memeriksa stdlib.htajuknya dan tidak disebutkan. Saya menggunakan MCC18.

Adakah yang harus menggunakannya?

Saya membutuhkannya karena saya porting perpustakaan dari Windows XP ke PIC. Panduan porting mengatakan untuk

menyesuaikan fungsi spesifik Sistem Pengoperasian dengan fungsi PIC saya

Tapi saya tidak tahu bagaimana "menerjemahkan" malloc()dan free()fungsinya.

Stefan
sumber
4
Coba gunakan alokasi statis jika memungkinkan.
Nick T
1
Mengapa? Masalahnya sebenarnya adalah bahwa saya sedang menulis lapisan bawah (platform khusus) dari perpustakaan yang cukup besar dan banyak fungsi yang saya tidak tahu untuk apa mereka menggunakan ini .. dan saya tidak tahu bagaimana cara mengubah dari dinamis ke statis ..
stef
11
Kedengarannya seperti mikrokontroler PIC dengan <4KB RAM mungkin salah untuk aplikasi Anda. Pada PC, ukur penggunaan memori perpustakaan PC Anda sebelum memulai porta. Anda mungkin lebih baik dengan sesuatu yang lebih gemuk seperti ARM Cortex-M3. Rule of thumb: jika basis kode yang Anda porting terlalu besar untuk dipahami maka tidak akan muat dalam PIC.
Toby Jaffey
Driver Windows (dan aplikasi pada umumnya) pada dasarnya ditulis dengan paradigma 'RAM tidak terbatas', karena jika RAM fisik habis, memori virtual dapat ditukar. Tergantung pada apa yang dilakukan perpustakaan, mungkin sangat baik mengkonsumsi lebih dari 4kB tersedia di PIC18F87J11 Anda. Saya menduga Anda tidak akan dapat mengukur berapa banyak memori yang akan digunakan pengemudi.
Adam Lawrence
Masalah potensial lain: int Win32 adalah 32 bit, sedangkan dengan kompiler MCC18, hanya 16 bit. Anda bisa mendapatkan masalah luapan aneh jika Anda tidak hati-hati.
Adam Lawrence

Jawaban:

8

Dalam banyak aplikasi, seseorang perlu mengalokasikan memori, tetapi tidak perlu membebaskan apa pun sambil menjaga sesuatu yang dialokasikan setelah itu. Pada sistem seperti itu, yang perlu dilakukan hanyalah menggunakan linker untuk mendefinisikan array menggunakan semua RAM yang tersedia, mengatur pointer ke awal array itu, dan kemudian menggunakan fungsi malloc mudah yang bagus:

char * next_alloc;
batal * malloc (ukuran int)
{
    char * this_alloc;
    this_alloc = next_alloc;
    if ((END_OF_ALLOC_SPACE - this_alloc) <size)
      return -1;
    next_alloc + = ukuran;
    kembalikan this_alloc;
}
void gratis (void * ptr)
{
    jika (ptr)
        next_alloc = (char *) ptr;
}

Bagus dan mudah, dan hanya dua byte total overhead untuk sejumlah alokasi. Menelepon gratis () pada blok akan membatalkan alokasi blok itu dan semuanya setelahnya.

Pola alokasi yang sedikit lebih rumit dapat ditangani dengan menggunakan dua petunjuk - satu yang mengalokasikan hal-hal dari bagian bawah memori bergerak ke atas, dan satu di antaranya bergerak dari bagian atas memori ke bawah. Dimungkinkan juga untuk menggunakan pemulung sampah yang kompak jika data dalam tumpukan itu homogen dan ada yang tahu di mana semua referensi luar untuk itu.

supercat
sumber
Untuk mendapat informasi lengkap tentang kemungkinan, bacalah jawabannya di electronics.stackexchange.com/questions/7850/…
gavioto20
14

malloc()dalam mikrokontroler umumnya dianggap sebagai "hal buruk". Tetapi, jika Anda benar-benar membutuhkannya maka Anda akan ingin menemukan versi pihak ketiga.

Jika Anda beruntung, kode yang Anda porting mungkin tidak bergantung pada penggunaan kembali blok memori. Jika demikian, Anda dapat menulis pengalokasi sederhana yang mengembalikan pointer ke buffer RAM, lalu memajukan pointer dengan ukuran blok yang diminta.

Saya telah berhasil menggunakan pendekatan ini sebelumnya dalam porting pustaka PC ke mikrokontroler.

Di bawah, Anda akan menyiapkan pengalokasi dengan my_malloc_init()dan mengalokasikan memori dengan my_malloc(). my_free()ada untuk memenuhi ketergantungan tetapi tidak akan benar-benar melakukan apa pun. Akhirnya Anda akan kehabisan ruang, tentu saja.

Agar ini berfungsi, Anda harus mengukur kebutuhan memori terburuk dari kode Anda (lakukan ini pada PC jika memungkinkan) kemudian atur HEAP_SIZEsesuai kebutuhan. Sebelum memasuki bagian perpustakaan Anda yang membutuhkan memori dinamis, hubungi my_malloc_init(). Sebelum digunakan kembali, pastikan tidak ada yang menunjuk heap.

uint8_t heap[HEAP_SIZE];
uint8_t *heap_ptr;

void my_malloc_init(void)
{
    heap_ptr = heap;
}

void *my_malloc(size_t len)
{
    uint8_t *p = heap_ptr;
    heap_ptr += len;
    if (heap_ptr >= heap + HEAP_SIZE)
        return NULL;
    else
        return p;
}

void my_free(void)
{
    // do nothing
}

(catatan: di dunia nyata, Anda mungkin perlu mempertimbangkan penyelarasan pointer, mis. pembulatan heap_ptrsebesar 2 atau 4 byte)

Pilihan lain adalah menggunakan struktur alokasi yang lebih sederhana daripada malloc()biasanya, seperti FreeList , meskipun ini mungkin tidak memungkinkan Anda untuk mengalokasikan blok berukuran variabel.

Toby Jaffey
sumber
3
Saya ingin tahu kapan malloc dianggap sebagai hal yang baik dalam embedded.
Kellenjb
1
Saya masih setuju Anda tidak ingin alokasi dinamis dalam program, seperti yang orang lain katakan, tapi ini cara yang bagus untuk melakukannya. Malloc pihak ketiga yang dirancang untuk disematkan sejauh ini merupakan pilihan terbaik. Menghindari segmentasi adalah suatu keharusan. @jobyTaffey Ditulis dengan baik.
Kortuk
1
@Kellenjb, itu pertanyaan baru :-)
Toby Jaffey
1
Saya menyarankan agar my_free harus menetapkan heap_ptr ke nilai yang lewat, secara efektif membebaskan item yang ditunjukkan dan semua yang dialokasikan setelahnya. Jelas seseorang harus mengalokasikan hal-hal dalam urutan yang memungkinkan penggunaan seperti itu, tetapi pola seperti itu tidak biasa. Variasi lain yang bermanfaat adalah memiliki dua pasang fungsi alokasi / bebas, yang satu mengalokasikan top-down dan yang lain mengalokasikan bottom-up.
supercat
13

Ini bukan jawaban untuk pertanyaan Anda, tetapi alokasi memori dinamis umumnya disukai pada lingkungan RAM kecil dan dengan tidak adanya sistem operasi (misalnya dalam dunia mikrokontroler) ... ... ruang tumpukan yang Anda miliki di lingkungan tertanam biasanya diukur dalam ratusan byte ...

Menerapkan malloc dan gratis pada dasarnya adalah pemeliharaan dari daftar terkait struktur "segmen bebas", dan seperti yang dapat Anda bayangkan, metadata yang terkait dengan segmen bebas tidak substansial bila dibandingkan dengan jumlah memori yang biasanya tersedia ... yaitu "overhead" "Mengelola kumpulan memori dinamis mengkonsumsi sejumlah besar sumber daya yang tersedia.

vicatcu
sumber
Ada implementasi di mana metadata overhead sangat kecil. Untuk blok yang dialokasikan, Anda hanya perlu ukurannya. Untuk blok yang tidak digunakan, pointer daftar tertaut (s) biasanya dapat ditampung secara gratis, bahkan dengan ukuran blok minimal yang cukup masuk akal.
Pasang kembali Monica
Masalah dengan sistem berjalan kecil dan panjang yang menggunakan mikrokontroler biasanya bukan tentang metadata, tetapi tentang fragmentasi memori. Yang lebih buruk, perubahan kecil pada kode Anda dapat menyebabkan fragmentasi memori yang sebelumnya tidak ada, sehingga Anda dapat membuat perubahan yang tampak tidak bersalah yang tiba-tiba membuat program Anda berhenti bekerja "terlalu cepat".
Pasang kembali Monica
11

Saya tidak tahu apakah pustaka standar C18 mendukung mallocdan free, tetapi Microchip App Note AN914 menunjukkan bagaimana Anda dapat menerapkannya sendiri.

Bagaimanapun, Thomas dan poster lainnya telah menyarankan, menggunakan memori dinamis pada PIC dengan ruang RAM yang sangat kecil penuh dengan bahaya. Anda dapat dengan cepat kehabisan ruang yang bersebelahan karena kurangnya manajer memori virtual yang lebih maju yang memberikan OS penuh sesak nafas, yang mengarah ke alokasi dan crash yang gagal. Lebih buruk lagi, itu mungkin tidak deterministik, dan kemungkinan akan merepotkan.

Jika apa yang Anda lakukan benar-benar ditentukan secara dinamis pada saat run-time (jarang untuk hal-hal yang tertanam), dan Anda hanya perlu mengalokasikan ruang pada beberapa acara yang sangat istimewa , saya bisa melihat mallocdan freediterima.

Nick T
sumber
Kehabisan ruang yang berdekatan, alias tumpukan tumpukan, adalah masalah yang sepenuhnya independen dari seberapa besar ruang alamat Anda dan apakah Anda memiliki memori virtual. Anda mungkin ingin menukar beberapa RAM yang terbuang untuk fragmentasi tumpukan yang lebih rendah, tetapi pada akhirnya, pada sistem yang berjalan lama, Anda tidak memiliki jaminan untuk tidak kehabisan ruang tumpukan. Satu-satunya perbedaan antara sistem kecil dan besar di sini adalah salah satu dari berapa lama waktu yang dibutuhkan untuk disk untuk mulai meronta-ronta (pada sistem dengan VM disk-paged), atau pengalokasi untuk mengembalikan NULL (pada hal-hal yang tertanam).
Pasang kembali Monica
@KubaOber: Secara umum dimungkinkan untuk menjamin bahwa RAM dengan ukuran tertentu akan dapat menangani setiap urutan alokasi dan melepaskan operasi yang tidak pernah membutuhkan lebih dari jumlah tertentu (lebih kecil) dari RAM yang dialokasikan secara bersamaan. Masalah dengan sistem tertanam adalah bahwa keberhasilan yang dijamin bahkan dalam kasus terburuk akan membutuhkan lebih banyak RAM daripada yang diperlukan tanpa fragmentasi.
supercat
@supercat Anda benar. Aku memang terlalu dramatis. Ada bukti formal dari jaminan itu.
Pasang kembali Monica
2

Nah, seberapa besar PIC Anda dalam hal memori?

malloc adalah cara yang sangat tidak efisien dalam mengalokasikan memori. Masalahnya adalah memori dapat menjadi terfragmentasi dengan sering membebaskan dan mallocs dan dengan hanya beberapa kilobyte memori, kegagalan alokasi terlalu umum. Sangat mungkin bahwa jika Anda menggunakan chip yang lebih kecil atau PIC18 sebelumnya tidak ada dukungan untuk malloc, karena Microchip memandangnya sebagai sangat sulit untuk diterapkan (atau mungkin bahkan tidak mungkin dalam beberapa kasus) atau tidak cukup digunakan untuk menjadi setimpal. Belum lagi, tetapi juga cukup lambat, Anda sedang melihat 1 siklus untuk menggunakan buffer statis yang sudah tersedia dan 100 untuk 1.000-an siklus untuk melakukan malloc.

Jika Anda ingin mengalokasikan secara statis, buat hal-hal seperti buffer untuk fungsi sprintf Anda (jika ada, sekitar 128 byte), buffer untuk kartu SD Anda (jika ada), dan seterusnya, hingga Anda menghapus kebutuhan untuk malloc. Idealnya, Anda hanya menggunakannya di mana Anda benar-benar membutuhkannya dan tidak dapat pergi dengan alokasi statis, tetapi situasi ini biasanya jarang dan mungkin pertanda bahwa Anda harus melihat mikrokontroler yang lebih besar / lebih kuat.

Dan jika Anda mengembangkan / porting "sistem operasi" pada PIC18 dan jika itu mendukung mikrokontroler mungkin memiliki dukungan untuk alokasi statis. Sebagai contoh, SQLite3 mendukung alokasi statis - Anda mengalokasikannya buffer array besar dan menggunakannya jika memungkinkan, meskipun bukan untuk mikrokontroler. Jika tidak, maka apakah Anda yakin itu dirancang untuk PIC18 kecil?

Thomas O
sumber
Saya mengerti maksud Anda .. Saya menggunakan PIC18F87J11, yang memiliki 128K ram, apakah cukup?
stef
Stefano, chip itu memiliki 3.904 byte RAM. Ini memiliki 128K memori program flash.
W5VO
@Stefao Salati - 3.8KB kecil.
Thomas O
Benar maaf .. apakah menurut Anda itu cukup?
stef
@Stefano Salati, tidak perlu meminta maaf. Saya pikir Anda akan benar-benar mendorongnya. Ini mungkin bekerja, tetapi itu akan mengambil sebagian dari kinerja dan memori bebas Anda.
Thomas O
2

Jika Anda mempertimbangkan malloc()dan free()untuk perangkat lunak tertanam Anda, saya sarankan Anda melihat uC / OS-II dan OSMemGet()dan OSMemPut(). Meskipun malloc()memungkinkan Anda mengalokasikan blok memori yang sewenang-wenang, OSMem*()memberi Anda blok berukuran tetap dari kumpulan yang dialokasikan sebelumnya. Saya menemukan pendekatan ini keseimbangan yang baik antara fleksibilitas malloc()dan ketahanan alokasi statis.

trondd
sumber
0

AFAIK, untuk melakukan ini dengan benar, Anda benar-benar harus melihat perangkat dengan beberapa jenis unit manajemen memori (MMU). Meskipun mekanisme alokasi dinamis untuk seri PIC18 memang ada, mereka tidak benar-benar akan sekokoh itu - dan berbicara sebagai seseorang yang bekerja pada firmware yang mendorong batas-batas seri PIC18, saya dapat mengatakan bahwa Anda tidak akan mendapatkan aplikasi yang cukup besar di sana jika Anda menghabiskan semua overhead pada manajer memori.

Solusi yang lebih baik: cobalah memahami apa yang dilakukannya, dan mengapa perlu alokasi yang dinamis. Lihat apakah Anda tidak dapat memfaktorkan ulang faktor itu agar berfungsi dengan alokasi statis. (Mungkin ini masalahnya tidak mungkin - jika perpustakaan / aplikasi dirancang untuk melakukan sesuatu yang berskala bebas, atau tidak memiliki batasan jumlah input yang dapat diterimanya.) Tetapi kadang-kadang, jika Anda benar-benar berpikir tentang apa yang Anda coba lakukan, Anda mungkin menemukan itu mungkin (dan mungkin bahkan cukup mudah) untuk menggunakan alokasi statis sebagai gantinya.

andersop
sumber
1
Anda salah. MMU memungkinkan Anda berinteraksi dengan memori eksternal (kemungkinan lebih dari 4kB pada PIC). Ada sedikit perbedaan dalam alokasi dinamis dan statis dengan dan tanpa MMU. Setelah Anda mulai masuk ke memori virtual, ada perbedaan, tapi itu hanya terkait dengan malloc.
Kevin Vermeer
1
Pemrogram Macintosh awal menggunakan malloc () dan free () (atau Pascal equivalents mereka) cukup sering, terlepas dari kenyataan bahwa komputer Macintosh awal tidak memiliki MMU. Gagasan bahwa "benar" menggunakan malloc () membutuhkan MMU tampaknya salah bagi saya.
davidcary