Tuesday, July 26, 2011

MEMORY MANAGEMENT




Beberapa bagian dari RAM digunakan oleh ke

rnel untuk menyimpan kode kernel dan struktur data statis kernel. Sisa dari bagian yang digunakan oleh kernel tersebut disebut dynamic memory. Dynamic memory ini tidak hanya digunakan oleh proses, tetapi juga oleh kernel senidri. Kualitas pe

rformansi dari keseluruhan sistem tergantung pada seberap

a efisien manajemen dynaimc memory. Manajemen mem

ori yang akan dibahas berikut menggambarkan bagaimana kernel mengalokasikan memori untuk keperluannya. Macam teknik manajemen memori :


1. Physically contigous memory areas

a. Page Frame Management

  1. Memory Area Management

  1. Physically noncontigous memory areas


a. Noncontigous Memory Area Management



Contiguous Memory Area Management


Page Frame Management




Linux menggunakan ukuran page frame 4KB sebagai standar untuk memory alocation unit, alasannya :

  1. Kernel bisa langsung mengetahui memory allocation unit di mana page fault terjadi.

  2. Ukuran 4KB merupakan kelipatan terkecil dari hampir seluruh ukura

    n blok disk.

Page frame descriptor diinisialisasi oleh fungsi free_area_init(), yang mempunyai 2 parameter : start_mem dan end_mem.

Kemudian fungsi mem_init() mengosongkan flag PG_reserved , dan flag PG_DMA dari semua page frame yang mempunyai alamat fisik sama dengan atau lebih besar dari 0x1000000.

Gambar 2 : Layout Memori



Requesting & Releasing Page Frame

Page frame bisa direquest dengan fungsi dan makro berikut :

  • _ _get_free_pages(gfp_mask, order), untuk merequest 2order page frame kontigu.

  • _ _get_dma_pages(gfp_mask, order), makro untuk mendapatkan page frame yang cocok untuk DMA; berkembang menjadi : _ _get_free_pages(gfp_mask | GFP_DMA, order).

  • _ _get_free_page(gfp_mask), makro untuk mendapatkan page frame tunggal, berkembang ke : _ _get_free_pages(gfp_mask, 0).

  • get_free_page(gfp_mask), fungsi yang

    memanggil _ _get_free_page(gfp_mask) dan kemudian mengisi page frame yang didapatkan dengan 0


Page frame bisa dibebaskan (direlease) melalui fungsi dan makro berikut :

  • free_pages(addr, order), fungsi yang mengecek page

    descriptor dari page frame yang mempunyai alamat fisik addr.

  • _ _free_page(p), membebaskan page frame yang descriptornya ditunjuk oleh parameter p.

  • free_page(addr), makro untuk membebaskan page frame dengan alamat fisik addr, berkembang ke free_pages(addr, 0).



Parameter gfp_mask menspesifikasikan bagaimana mencari page frame yang bebas. Terdiri atas flag – flag :

  • _ _GFP_WAIT , diset apabila kernel diijinkan untuk membuang isi page frame untuk membebaskan memori sebelum memenuhi request.

  • _ _GFP_IO, diset apabila kernel diijinkan untuk menulis page ke disk dengan tujuan membebaskan page frame yang bersangkutan.

  • _ _GFP_DMA, diset apabila page frame yang diminta harus sesuai untuk DMA.

  • _ _GFP_HIGH, _ _GFP_MED, _ _GFP_LOW, me

    nspesifikasikan prioritas request. _ _GFP_LOW biasanya diasosiasikan dengan request dynamic memory oleh proses User Mode, dan prioritas yang lain diasosiasikan dengan request dari kernel.



Buddy System Algorithm

Teknik yang digunakan linux untuk mengatasi fragmentasi eksternal adalah algoritma sistem buddy.


Sistem Buddy merupakan cara mengelola memori utama dengan memanfaatkan kelebihan penggunaan bilangan biner.

Semua page frame dibagi menjadi 10 list blok yang terdiri dari group 1, 2, 4, 8, 16, 32, 64, 128, 256, dan 512 page frame yang kontigu, secara berurutan : alamat page frame pertama dari blok merupakan kelipatan dari ukuran group, misalnya, blok frame 16 merupakan kelipatan dari 16 × 212

Misalnya suatu memori utama pada awalnya me

miliki satu lubang besar berukuran 1 Mbyte. Jika suatu proses A berukuran 90Kbyte memasuki memori, maka permintaan 90 Kbyte akan dialokasikan ke lokasi terdekat yang dapat memuatnya yaitu 128 Kbyte. Karena tidak tersedia blok ukuran 128, maka blok 1 Mbyte dipecah menjadi 2 blok masing-masing berukuran 512 Kbyte. Blok ini dibagi lagi menjadi blok-blok berukuran 256 Kbyte, selanjutnya masih dibagi menjadi blok-blok 1

28 Kbyte. Kemudian Proses B yang berukuran 50 Kbyte akan menempati lubang 64 Kbyte berikutnya dengan cara membagi blok 64 Kbyte. Jika tidak ada blok yang dapat dialokasikan maka akan melaporkan error.


Dengan menggunakan sistem buddy ini akan mudah melakukan dealokasi proses. Jika suatu proses dibebaskan, kernel akan melakukan penggabungan dari pasangan blok buddy yang bebas dengan ukuran b ke dalam blok tunggal dengan ukuran 2b. Dua blok dapat digabung jika kedua buddy mempunyai ukuran yang sama, dialokasikan pada alamat fisik yang kontigu, dan alamat fisik dari page pertama dari blok pertama merupaka kelipatan dari 2b x 212. Penggabungan ini dilakukan secara iteratif.

          1. Struktur Data


Linux menggnakan 2 sistem buddy yang berbeda. Satu sistem untuk meng-handle page frame yang sesuai untuk ISA DMA, sementara yang lainya meng-handle page frame yang tersisa. Masing-masing sistem buddy ini menggunkan struktur data :

  • array mem_map (array yang mengandung page frame descriptor).

  • array yang mempunyai 10 elemen dengan tipe free_area_struct, satu elemen untuk tiap ukuran group. Variabel free_area[0] menunjuk pada array yang digunakan sistem buddy untuk page frame yang tidak sesuai untuk ISA DMA

    , sementara free_area[1] menunjuk pada array yang digunakan sistem buddy untuk page frames yang sesuai untuk ISA DMA.

  • 10 array biner yang dinamakan bitmaps, 1 untuk tiap ukuran group. Tiap-tiap sistem buddy mempunyai himpunan bitmapsnya sendiri yang digunakan untuk menjaga track dari blok yang dialokasikan.



          1. Allocation


Untuk mengalokasikan suatu page frame, sistem buddy menggunakan function __get_free_pages().


Algoritma : Pertama mengecek apakah ada ruang yang cukup, yaitu jika nr_free_pages lebih besar daripada freepages.min. Jika tidak, maka perlu mendapatkan kembali page frame, atau tetap mengalokasikan dengan mengeksekusi kode y

ang terkandung di macro RMQUEUE_TYPE. Jika page frame telah dialokasikan, kode di macro RMQUEUE_TYPE mengeksekusi return statement, lalu menterminasi function __get_free_pages(). Kemudian jika kode pada RMQUEUE_TYPE dieksekusi lagi dengan parameter kedua = 1, maka request untuk alokasi memori dipenuhi dengan menggunakan page frame yang sesuai dengan DMA.

Macro kemudian melakukan pencarian blok yang tersedia pada list. Jika loop while (untuk search) selesai, jika tidak ada blok yang cocok yang ditemukan, maka __get_free_pages() mengembalikan nilai NULL, jik

a blok yang sesuai ditemukan, maka descriptor dari page frame pertama dihapus dari list, kemudian bitmap yang sesuai di update, dan melakukan decreament pada nilai nr_free_pages. Jika blok yang ditemukan berasal dari list mempunyai ukuran new_order lebih besar daripada ukurang yang direquest, loop while di eksekusi. Akhirnya, RMQUEUE_TYPE meng-update counter untuk page descriptor yang diasosiasikan dengan blok yang dipilih dan mengeksekusi instruksi hasil. Sebagai

hasilnya, function __get_free_pages() mengembalikan nilai alamat dari blok yang ditemukan


          1. Deallocation


Sistem buddy menggunakan function free_pages_ok() untuk membebaskan page frame dengan menggunakan 3 parameter input.

    • map_nr, yaitu nomor page dari salah satu page frame yang terkandung dari blok yang akan dibebaskan.

    • order, yaitu ukuran logik blok


    • type, biner, 1 jika page frame sesuai untuk DMA dan 0 jika tidak


Algoritma : Fungsi ini dimulai dengan men-declare dan menginisialisasi local variable.


struct page *next, *prev;

struct free_area_struct *area =&free_area[type][order];

unsigned long index = map_nr >> (1 + order);

unsigned long mask = (~0UL) << order;

unsigned long flags;


variabel mask mengandung komplemen dua dari 2order yang digunakan untuk mengubah map_nr ke dalam nomor dari page frame pertama blok yang dibebaskan dan untuk melakukan increament nr_free_pages.

Kemudian fungsi mulai mengeksekusi cycle paling banyak (9-order), satu kali untuk tiap kemungkinan untuk menggabungkan blok dengan buddynya. Di dalam body loop dilakukan pengecekan apakah buddy dari blok yang mempunyai map_nr bebas atau tidak. Pada akir iterasi, fungsi melakukan update terhadap mask, area, index, dan map

_nr. Kemudian fungsi ini melanjutkan pada iterasi selanjutnya, mencoba untuk menggabungkan blok-blok bebas untuk yang kedua kalinya menjadi satu blok bebas dengan ukuran yang lebih besar.



Memory Area Managemet



Manajemen memory area ini digunakan untuk mengatasi request untu memory area dengan ukuran kecil. Dengan adanya manajemen memory area maka internal fragmentation yang terjadi akibat adanya sistem buddy dapat dikurangi. Untuk iu digunakan algoritma slab allocator.

The Slab Allocator

Algoritma ini menggambarkan memory area sebagai objek-objek yang terdiri dari struktur data dan pasangan metode, yaitu constructor yang berfungsi untuk menginisialisasi memory area, dan destructor yang berfungsi untuk meng-deinisialisasi memory area. Objek-objek yang ada dikelompokkan ke dalam caches. Area dari main memory terdiri dari suatu cache yang dibagi menjadi slab-slab yang terdiri dari satu atau lebih page frame yang kontigu yang juga terdiri dari dari objek yang sudah dialokasikan dan yang masih bebas.


Gambar 3 : Keterhubungan Cache, Slab dan Objek



Slab allocator tidak pernah membuang objek yang telah dialokasikan, namun membebaskannya tetapi tetap menyimpannya di dalam memory. Hal ini dilakukan agar ketika ada request untuk objek baru maka dapat diambil dari memori tanpa melakukan inisialisasi ulang. Jadi secara umum, tujuan dari penggunaan slab allocator ini adalah untuk mengurangi pemanggilan buddy sistem allocator.

Kernel function cenderung untuk me-request memory area dengan tipe yang sama secara berulang-ulang sehingga tidak perlu melakukan alokasi dan dealokasi page frame yang mengandung memory area yang sama secara berulang-ulang, tetapi cukup dengan menyimpannya dalam cache dan menggunakan ulang ketika diperlukan.


Cache Descriptor

Tiap cache descriptor terdiri dari tabel dengan struktur data :

  • c_name, menunjuk nama dari cache

  • c_firstp, c_lastp, menunjuk first dan last slab descriptor dari cache.

  • c_freep, menunjuk slab descriptor pertama yang setidaknya mengandung satu objek bebas.

  • c_num, merupakan jumlah objek dalam satu slab tunggal. Semua slab dari suatu cache mempunyai ukuran yang sama.

  • c_offset, merupakan ukuran dari objek yang terkandung dalam suatu cache.

  • c_gfporder, angka logaritma dari jumlah page frame kontigu yang terdapat pada suatu slab tunggal.

  • c_ctor, c_dtor, menunjuk pada constructor dan destructor

  • c_nextp, menunjuk next cache descriptor

  • c_flags, suatu array flag yang mendeskripsikan beberapa permanent dari cache.


  • c_magic, mengandung magic number yang digunakan untuk mengecek keadaan suatu cache pada saat ini dan konsistensinya.


Slab Descriptor

Tiap slab pada cache mempunyai deskriptornya masing-masing dengan type struct kmem_slab_s. Field-field yang penting pada suatu slab descriptor antara lain :

  • s_inuse, merupakan jumlah objek pada slab yang sedang dialokasikan.


  • s_mem, menunjuk pada objek pertama pada slab, baik yang sudah dialokasikan ataupun yang masih bebas.

  • s_freep, menunjuk objek bebas pertama pada slab jika ada.

  • s_nextp, s_prevp, menunjuk next dan previous slab descriptor.


  • s_dma, diset oleh flag untuk menunjukkan bahwa objek pada slab dapat digunakan oleh DMA.

  • s_magic, mengandung magic number yang digunakan untuk mengecek keadaan suatu slab pada saat ini dan konsistensinya.

Slab descriptor disimpan dengan dua kemungkinan tergantung pada ukuran objek pada slab. Jika ukuran objek kurang dari 512 bytes, slab descriptor disimpan diakhir slab; dan sebaliknya jika ukuran objek dalam slab itu lebih dari 512 bytes maka slab descriptor disimpan di luar slab.



General And Specific Caches

Cache dibedakan menjadi dua jenis, yaitu general dan spesifik. General caches hanya digunakan oleh slab allocator untuk tujuannya, sementara cache spesifik digunakan oleh bagian lain dari kernel.

General caches terdiri dari :

  • Cache pertama yang terdiri dari cache deskriptor yang digunakan oleh kernel.

  • Cache kedua terdiri dari slab descriptor yang tidak disimpan dalam slab.

  • Tiga belas cache tambahan terdiri dari memori area yang terdistribusi secara geometri. Tabel dengan nama cache_sizes yang elemen-elemennya merupakan type cache_sizes_t yang menunjuk pada 13 cache descriptor yang diasosiasikan dalam memory area dengan ukuran : 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65

    536, dan 131072 bytes.

Specific caches dibuat oleh fungsi kmem_cache_sizes_init(). Berdasarkan parameter, fungsi ini pertama kali menentukan cara paling baik untuk meng-handle cache baru. Kemudian membuat cache descriptor untuk cache baru itu dan memasukkan descriptor ke dalam general cache cache_cache. Sekali cache sudah dibuat maka tidak dapat dihilangkan.


Allocating A Slab to A Cache

Cache yang baru dibuat tidak mengandung slab, oleh karena itu tidak mengandung objek bebas. Slab baru dapat di-assign ke dalam cache dengan syarat :

  • Request telah dikeluarkan untuk mengalokasikan objek baru.

  • Cache tidak mengandung objek bebas.


Ketika kedua syarat tersebut dipenuhi maka slab baru di-assign ke dalam cache dengan memanggil fungsi kmem_cache_grow(). Fungsi ini memanggil fungsi kmem_getpages() untuk mendapatkan kumpulan page frame dari buddy sistem, kemudian memanggil fungsi kmem_cache_slabmgmt() untuk mendapatkan slab descriptor baru. Kemudian memanggil fungsi kmem_cache_init_objs() yang menggunakan metode constructor kepada semua objek yang dikandung pada slab baru. Kemudian memanggil fungsi kmem_slab_link_end() yang memasukkan slab descriptor pada akhir list slab pada cache (insert last).


Releasing a Slab from a Cache

Slab allocator tidak pernah membebaskan page frame dari slab yang kosong, namun slab dapat dibebaskan hanya jika :

  • Buddy system tidak mampu memenuhi request page frame.

  • Slab kosong, dan semua objek yang dikandungnya bebas.


Ketika kernel mencari page frame bebas tambahan, maka kernel memanggil fungsi try_to_free_pages(). Fungsi ini mungkin memanggil fungsi kmem_cache_reap() yang memilih cache yang sedikitnya mengandung satu slab kosong. Kemudian fungsi kmem_slab_unlink() menghapus slab dari list. Kemudian dihilangkan sama sekali dengan menggunakan fungsi kmem_slab_destroy().


Object Descriptor

Seperti halnya slab descriptor, objek descriptor juga dapat disimpan dalam dua cara, yaitu:

  • External object descriptor

Objek descriptor disimpan di luar slab.

  • Internal object descriptor


Objek descriptor disimpan di dalam slab, ditempatkan sesudah objek yang dideskripsikannya.

Slab allocator akan menggunakan cara pertama (External object descriptor) jika ukuran objek kelipatan dari 512, 1024, 2048, atau 4096 karena jika untuk ukuran tersebut objek disimpan di dalam slab maka kemungkinan adanya internal fragmentation semakin besar. Jika ukuran objek kurang dari 512 bytes atau bukan merupakan kelipatan dari 512, 1024, 2048, atau 4096, maka objek tersebut disimpan di dalam slab.

Struktur data dari objek descriptor :

typedef struct kmem_bufctl_s {

union {

struct kmem_bufctl_s * buf_nextp;

kmem_slab_t * buf_slabp;

void * buf_objp;

} u;

} kmem_bufctl_t;

#define buf_nextp u.buf_nextp

#define buf_slabp u.buf_slabp

#define buf_objp u.buf_objp




buf_nextp, menunjuk objek bebas selanjutnya pada slab jika objek bebas.

buf_objp, menunjuk pada objek jika objek sudah dialokasikan dan objek descriptornya disimpan di luar slab.

buf_slabp, menunjuk pada slab descriptor dari slab dimana objek disimpan jika objek yang dialokasikan dan objek descriptornya disimpan di dalam slab.


Noncontiguous Memory Area Management


Pemetaan Memory area ke Page Frame yang kontigu lebih banyak digunakan karena penggunaan cache yang lebih maksimal dan waktu akses memori yang lebih rendah. Namun jika permintaan akses akan memori area jarang, maka alokasi berdasarkan page frame yang non kontigu melalui linier address yang kontigu dapat digunakan.

Keuntungan dari skema tersebut adalah menghindari external fragmentation. Hal ini dikarenakan penggunaan list yang besarnya telah ditentukan sebelum akan dialokasikan. Sedangkan kerugiannya adalah kita harus banyak berurusan dengan Page Table Kernel. Ukuran dari noncontiguous memory area merupakan kelipatan dari 4096. Linux menggunakan noncontiguous memory area untuk mengalokasikan struktur data untuk swap area aktif, alokasi space utnuk modul atau alokasi buffer untuk perangkat I/O.


Linier Address untuk Memori Area Nonkontigu

Untuk mencari interval linier address kita dapat memulai dari PAGE_OFFSET. PAG_OFFSET merupakan gigabyte keempat dari total 4 GB linier address yang bisa digunakan. Kita tahu bahwa Kernel menggunakan bagian awal dari memory dimulai dari PAGE_OFFSET ini. Namun itu hanya sebagian kecil saja. Semua linier address setelah bagian tersebut dapat bebas digunakan untuk memetakan noncontiguous memory area. Antara memory area yang satu dengan yang lain dipisahkan oleh interval 4-8 KB ( noncontiguous ).


Gambar 4 : Linier Address Gigabyte keempat


Deskriptor Memori Area Nonkontigu

Noncontiguous memory area dideskripsikan dengan struktur data vm_struct :


struct vm_struct {

unsigned long flags;

void *addr;

unsigned long size;

struct vm_struct *next; };


Deskriptor ini memiliki next yang mendefinisikan area selanjutnya. Address dari first element disimpan di variabel vmlist. Sedangkan addr menyimpan linier address untuk memory cell area yang pertama dan size menyimpan ukuran + 4096.

Fungsi get_vm_area () digunakan untuk membuat deskriptor baru dari tipe vm_struct tadi. Parameternya adalah size yang menspesifikasikan ukuran dari memory area yang diinginkan.

Fungsi get_vm_area () pertama kali memanggil kmalloc () untuk memperoleh memory area dari deskriptor yang baru. Fungsi tersebut mencari range linier yang memungkinkan untuk dialokasi dengan ukuran size + 4096. Jika range tersebut ada, maka fungsi tersebut akan mengembalikan initial address dari noncontiguous memory area dan jika gagal akan mengembalikan NULL.


Alokasi Memori Area Nonkontigu

Fungsi vmalloc () digunakan untuk mengalokasikan sebuah noncontiguous memory area pada kernel. Parameter yang digunakan adalah size yang menyatakan ukuran. Jika fungsi ini berhasil maka akan mengembalikan initial linier address dari area yang baru atau mengembalikan NULL jika gagal.

Pertama kali fungsi vmalloc () akan didekatkan ke kelipatan dari 4096. Selain itu akan diperiksa apakah size tadi > 0 dan <= jumlah page frame yang tersedia. Jika syarat tersebut dipenuhi maka vmalloc () akan memanggil fungsi get_vm_area () yang menciptakan deskriptor dan mengembalikan linier address yang diassign ke memory area. Lalu vmalloc () akan memanggil vmalloc_area_ pages () untuk merequest noncontiguous page frame dan diterminasi dengan mengembalikan initial linier address dari noncontiguous memory area.



Fungsi vmalloc_area_ pages () menggunakan 2 parameter : address, sebagai initial linier address dari area dan size sebagai ukuran. Akhir dari linier address merupakan penjumlahan dari address dengan size.

Fungsi vmalloc_area_ pages () menggunakan makro pgd_offset_k untuk menurunkan entry di Page Global Direktory yang berhubungan dengan initial address dari area yang dialokasi. Lalu fungis vmalloc_area_pages () tersebut dalam setiap siklusnya memanggil pmd_alloc_kernel () untuk membuat Page Middle Directory untuk area yang baru lalu memanggil alloc_area_pmd () untuk mengalokasikan semua Page Table yang berhubungan dengan Page Middle Directory baru tadi. Selanjutnya set_pgdir () dipanggil untuk mengupdate entry yang berkorespondensi dengan Page Middle Directory yang baru di semua Page Global Directories yang ada. Siklus ini berlangsung hingga semua Page Table entries yang merujuk ke noncontiguous memory area baru berhasil diset.

Dalam alloc_area_pmd () dipanggil pte_alloc_kernel () yang mengalokasikan Page Table yang baru dan mengupdate entry yang berkorespondensi dalam Page Middle Directory. Selanjutnya alloc_area_pte () mengalokasikan semua page frame yang berkorespondensi dengan entry di Page Table.

Setiap page frame dialokasikan melalui fungsi __get_free_page () yang dipanggil dalam alloc_area_pte (). Alamat fisik dari page frame yang baru ditulis ke dalam Page Table dengan macro set_pte dan mk_pte.


Releasing Memori Area Nonkontigu

Untuk membebaskan noncontiguous memory area digunakan fungsi vfree (). Parameter yang digunakan adalah addr yang berisi initial linier address area yang akan dibebaskan.

Pertama kali vfree () akan mencari area deskriptor yang berasosiasi dengan area yang akan dibebaskan. Size dari deskriptor mendefinisikan ukuran dari area yang akan dibebaskan. Area itu sendiri dibebaskan dengan fungsi vmfree_area_pages () sedangkan deskriptornya dengan fungsi kfree ().

Fungsi vmfree_area_pages () menggunakan 2 parameter : initial linier address dan size area. Di dalamnya akan memanggil free_area_pmd () yang merupakan kebalikan aksi dari alloc_area_pmd () dan free_area_pte () yang merupakan kebalikan aksi dari alloc_area_pte ().

Tiap page frame yang dialokasikan ke noncontiguous memory area dibebaskan dengan fungsi free_page () dan entry yang berkorespondensi di Page Table diset 0 dengan makro pte_clear.

No comments:

Post a Comment