Skrivet av klk:
Det här uttalandet förstår inte jag. Du vet själv hur assembler fungerar. Du (och jag) kan lätt granska vad det som sker under ytan och du och jag vet hur svårt det är att göra någon större skillnad i mindre lösningar.
Skulle man se stora skillnader i prestanda så är det inte samma funktionalitet, det kan man lätt räkna ut.
Självklart är det inte identisk funktionalitet, behövs inte assembler-analys för att fatta det. En använder GC och en använder manuell minneshantering t.ex. via RAII.
Grejen är att om man har fall där man frekvent behöver allokera minne så har en GC en fördel, by-design, i att dess allokeringslogik kan med fördel göras så den är lika snabb som en typisk arena-allokator. Och likt hur man optimerar högpresterande I/O-trafik, coalescing (många små väldigt snarlika uppgifter kombineras till en större), får GC, by-design, just ett sådant beteende i sin av-allokeringslogik.
"C++ programmerare löser detta just med arena-allokator" kanske är din invändning. Sure, om alla allokerade objekt har en begränsad och väldefinierad livslängd som är praktiskt användbar. Men inte alls ovanligt att ha fall där de flesta objekt har en relativt kort livslängd, medan vissa lever längre. Det kopplat med att det inte är möjligt att veta vilka som lever längre i förväg ger en klart prestandafördel till GC i ett inte alls osannolikt real-world use-case.
"Objekt" är här "minnesobjekt", inte objekt i typiskt OOP-sense.
Ovanpå detta finns en annan optimering som i alla fall JVM-språk och Go använder sig av frekvent relaterad till effektiv minneshantering: escape analysis.
Det kan också resultera i "högre prestanda än logiskt ekvivalent C++" då vissa heap-allokeringar kan ersättas med stack-allokeringar. Det kan i teorin (är inte hundra på om det görs i praktiken) spekulativt i fall där vissa vägar tillåter stack-allokering, medan andra låter objektet "rymma" och i det läget måste man flytta data till heap (logiskt är detta sätt att skriva kod idiomatiskt i Go, i.e. man allokerar på stacken och returnerar en pekare till data, känns fel som C/C++ programmerare då det är en inte helt sällsynt bug med rätt stora säkerhetsimplikationer...)
TL;DR Det finns absolut fall där GC kan vara mer effektivt jämfört med manuell minneshantering. Självklart finns också fall där manuell minneshantering kan vara effektivare än GC.
Skrivet av klk:
Kodar Rust utvecklare på det viset? Jag har inte sett det. Koden blir för "jobbig". Jag vet definitivt att denna typ av kod (själv skapa ett block och sköta det internt) inte existerar bland C# utvecklare. Skulle någon få för sig att skriva sådan kod är jag helt övertygad om att utvecklaren får kasta bort det.
Har jobbat med en hel del del C# utvecklare. Det är STOR skillnad i hur kod skrivs. Du får inte skena iväg och skriva för svårt. Och det skulle förvåna om det är tillåtet bland utvecklare i Rust.
Dessa "säkra" språk är inte gjorda för att leka med minnet. När det blir större och mer komplexa har de för länge sedan lämnat walk over. Koden blir för jobbig.
Varför skulle man inte göra så i Rust vid behov? En huvudanledning att använda Rust är just för man vill/behöver manuell minneshantering, t.ex. hård realtid.
Så här krångligt är det att använda en arena allokator. bumparo projektet hanteras av Alex Crichton och Nick Fitzgerald, båda är välkända profiler i Rust-världen, båda har bl.a. jobbat med standardbiblioteket i Rust.
Notera också att projektet har totalt 157M nedladdningar, så det är hyfsat populär crate.
Klicka för mer information
use bumpalo::Bump;
#[derive(Debug)]
struct Person {
name: String,
age: u8,
}
fn with_arena_allocator() {
let arena = Bump::new();
let mut persons = bumpalo::collections::Vec::new_in(&arena);
persons.push(Person {
name: "Arena Alice".to_string(),
age: 30,
});
persons.push(Person {
name: "Arena Bob".to_string(),
age: 40,
});
for person in persons.iter() {
println!("{:?}", person);
}
}
fn with_heap_allocator() {
let mut persons = Vec::new();
persons.push(Person {
name: "Heap Alice".to_string(),
age: 30,
});
persons.push(Person {
name: "Heap Bob".to_string(),
age: 40,
});
for person in persons.iter() {
println!("{:?}", person);
}
}
fn main() {
with_arena_allocator();
with_heap_allocator();
}
Visa mer
Och varför skulle inte C#-kod använda arena-allokator. Ser mig inte som en "C#-programmerare", finns flera språk jag föredrar över C#, men för tillfället sitter jag primärt just i C# på jobbet, i ett projekt som har en custom-designed arena-allokator inkluderat (använder C# för enda realistiska alternativen var C++ eller C#, hade hellre använt Go men fungerar tyvärr inte).
Men finns också arena-allokator alternativ på NuGet, t.ex. Varena.
Kanske sluta göra antaganden om brister och "vad som inte kan göras" i miljöer du aldrig använt?