Öbek ayırıcı
- Rust kursu
- Uzman
- Ders 43/46
- 7 dk
Kendi bellek ayırıcını unsafe ile yazarsın.
Bitirme görevi: öbek ayırıcı
Uzman seviyenin ilk bitirme görevi: programın tüm heap ayırmalarını sayan bir küresel ayırıcı. GlobalAlloc trait'i iki zorunlu metot ister: alloc ve dealloc. Sistem ayırıcısını sarıp her çağrıda atomik sayaçları güncelleyeceğiz:
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
struct Sayan;
static ADET: AtomicUsize = AtomicUsize::new(0);
static BAYT: AtomicUsize = AtomicUsize::new(0);
unsafe impl GlobalAlloc for Sayan {
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
ADET.fetch_add(1, Ordering::Relaxed);
BAYT.fetch_add(l.size(), Ordering::Relaxed);
unsafe { System.alloc(l) }
}
unsafe fn dealloc(&self, p: *mut u8, l: Layout) {
unsafe { System.dealloc(p, l) }
}
}
#[global_allocator]
static AYIRICI: Sayan = Sayan;Bir bloğu ölçmek
Sayaçların bloktan önceki ve sonraki farkı, o bloğun ayırmalarını verir. Ölçüm sırasında yazdırma yapmamak önemlidir, çünkü println! de ayırma yapabilir:
let (a0, b0) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
{
let v: Vec<u8> = Vec::with_capacity(100);
std::hint::black_box(&v);
}
let (a1, b1) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
println!("{} {}", a1 - a0, b1 - b0); // 1 100Bu teknik, sıcak döngülerdeki gereksiz ayırmaları bulmak için kullanılır; dhat crate'i aynı fikrin ayrıntılı bir sürümüdür.
Uygulama Sayan ayırıcı
Yukarıdaki Sayan ayırıcısını yaz ve kaydet. Vec::<u8>::with_capacity(100) oluşturan bir bloğun ayırma sayısını ve bayt miktarını, ölçüm sırasında yazdırma yapmadan hesapla ve boşlukla yazdır.
Başlangıç kodu
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
fn main() {
// buraya yaz
}Örnek çözüm
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
struct Sayan;
static ADET: AtomicUsize = AtomicUsize::new(0);
static BAYT: AtomicUsize = AtomicUsize::new(0);
unsafe impl GlobalAlloc for Sayan {
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
ADET.fetch_add(1, Ordering::Relaxed);
BAYT.fetch_add(l.size(), Ordering::Relaxed);
// SAFETY: sözleşme çağırandan System'e aynen aktarılır.
unsafe { System.alloc(l) }
}
unsafe fn dealloc(&self, p: *mut u8, l: Layout) {
// SAFETY: p, aynı layout ile System'den alınmıştı.
unsafe { System.dealloc(p, l) }
}
}
#[global_allocator]
static AYIRICI: Sayan = Sayan;
fn main() {
let (a0, b0) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
{
let v: Vec<u8> = Vec::with_capacity(100);
std::hint::black_box(&v);
}
let (a1, b1) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
println!("{} {}", a1 - a0, b1 - b0);
}Beklenen çıktı
1 100
Soru ve cevaplar
Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.
1 Ayırıcının içinde <code>println!</code> ya da <code>Vec</code> kullanmak neden tehlikelidir?
- Onlar da ayırma yapabilir; ayırıcı kendini özyinelemeli çağırıp kilitlenir ya da taşar Doğru cevap
- Yavaştır
- Derlenmez
- Tehlikeli değildir
Açıklama: Ayırıcı yalnızca ayırma gerektirmeyen işlemler yapmalı: atomik sayaçlar ideal.
2 Küresel ayırıcıyı kaydet
#[____]
static AYIRICI: Sayan = Sayan;
#[global_allocator]
static AYIRICI: Sayan = Sayan;
Açıklama: #[global_allocator] programın tüm heap ayırmalarını bu değere yönlendirir.
3 Öğe ve görevi
| Kavram | Anlamı |
|---|---|
GlobalAlloc |
Ayırıcı trait'i |
Layout |
Boyut ve hizalama |
System |
İşletim sistemi ayırıcısı |
#[global_allocator] |
Kayıt |