Hidup di jalur cepat



Dalam seri pertama tentang GC, saya memperkenalkan pengumpul sampah D dan fitur bahasa yang menggunakannya. Dua poin utama yang saya coba sampaikan:



  1. GC hanya berjalan saat Anda meminta alokasi memori . Berlawanan dengan kesalahpahaman populer, bahasa D GC tidak bisa hanya menghentikan dan menjeda klon Minecraft Anda di tengah-tengah loop permainan. Ini hanya berjalan ketika Anda meminta memori melaluinya dan hanya jika diperlukan.



  2. Strategi alokasi memori gaya C dan C ++ sederhana dapat mengurangi beban pada GC . Jangan mengalokasikan memori di dalam loop - sebagai gantinya, pra-alokasikan sumber daya sebanyak mungkin atau gunakan tumpukan. Minimalkan jumlah total alokasi memori melalui GC. Strategi ini berhasil karena # 1. Pengembang dapat menentukan kapan harus menjalankan pengumpulan sampah dengan cerdas menggunakan alokasi tumpukan yang dikelola GC.





Strategi dari poin # 2 baik untuk kode yang ditulis sendiri oleh programmer, tetapi mereka tidak terlalu membantu dalam hal perpustakaan pihak ketiga. Dalam kasus ini, menggunakan mekanisme bahasa D dan runtime-nya, Anda dapat memastikan bahwa tidak ada alokasi memori yang terjadi pada titik-titik kritis dalam kode. Ada juga opsi baris perintah untuk membantu memastikan GC tidak menghalangi Anda.



Mari kita bayangkan bahwa Anda sedang menulis program D dan karena satu dan lain hal memutuskan untuk menghapus seluruh pengumpulan sampah. Anda memiliki dua solusi yang jelas.



Pil untuk keserakahan



Solusi pertama adalah menelepon GC.disableketika program dimulai. Mengalokasikan memori melalui GC masih akan berfungsi, tetapi pengumpulan sampah akan berhenti. Semua pengumpulan sampah, termasuk apa yang mungkin terjadi pada utas lainnya.



void main() {
    import core.memory;
    import std.stdio;
    GC.disable;
    writeln("Goodbye, GC!");
}


Keluaran:



Goodbye, GC!


, , GC, , . , , , . , - . :



, , .

, . , - , . GC.enable GC.collect. , C C++.





, @nogc. main, .



@nogc
void main() { ... }


GC. @nogc, main, , . ยซ ยป.



, GC.disable. .



@nogc
void main() {
    import std.stdio;
    writeln("GC be gone!");
}


:



Error: @nogc function 'D main' cannot call non-@nogc function 'std.stdio.writeln!string.writeln'
(: @nogc- 'D main'    -@nogcโ€“ 'std.stdio.writeln!string.writeln')


@nogc , . . @nogc, , , @nogc. , writeln .



:



@nogc 
void main() {
    auto ints = new int[](100);
}


:



Error: cannot use 'new' in @nogc function 'D main'
(:   'new'  @nogc- 'D main')


@nogc- , GC ( ). . , , GC . , , @nogc, .



, @nogc , . , , - ( ). โ€” . :



throw new Exception("Blah");


- , new, @nogc- . , , , - , โ€ฆ , . D , , throw new Exception GC, .



, @nogc- . (. .)

@nogc main โ€” , .



, : @nogc main GC . D . main, โ€” . @nogc, , , GC @nogc-. , @nogc, main, , main , , GC.





. , D, GC . , GC โ€” . , , D: GC . , , .



, , , GC. @nogc / API core.memory.GC . @nogc main, , GC. GC.disable . , GC.enable. , GC (, ), GC.collect.



, , , . API core.memory.GC GC . D.



( !) D --DRT-gcopt=profile:1, . GC, , .



: gcstat.d .



void main() {
    import std.stdio;
    int[] ints;
    foreach(i; 0 .. 20) {
        ints ~= i;
    }
    writeln(ints);
}


GC:



dmd gcstat.d
gcstat --DRT-gcopt=profile:1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
        Number of collections:  1
        Total GC prep time:  0 milliseconds
        Total mark time:  0 milliseconds
        Total sweep time:  0 milliseconds
        Total page recovery time:  0 milliseconds
        Max Pause Time:  0 milliseconds
        Grand total GC time:  0 milliseconds
GC summary:    1 MB,    1 GC    0 ms, Pauses    0 ms <    0 ms


, , , . D GC , ( ) . , , D , GC - ( ).



DMD -vgc, GC โ€” , , ~=.



: inner.d.



void printInts(int[] delegate() dg)
{
    import std.stdio;
    foreach(i; dg()) writeln(i);
} 

void main() {
    int[] ints;
    auto makeInts() {
        foreach(i; 0 .. 20) {
            ints ~= i;
        }
        return ints;
    }

    printInts(&makeInts);
}


makeInts โ€” . , , / ( static, delegate function). .



-vgc:



dmd -vgc inner.d
inner.d(11): vgc: operator ~= may cause GC allocation
inner.d(7): vgc: using closure causes GC allocation

(inner.d(11): vgc:  ~=      GC)
(inner.d(7): vgc:        GC)


, , ints, ( โ€” - delegate). ints makeInts . , - . printInts :



void printInts(scope int[] delegate() dg)


scope , . , dg . , . . , , .





, GC D , Java C#, . , D , Java, . , D. , Java, GC , .



, , , , . D โ„– 2 , @nogc core.memory.GC , . , , , .



, D. , Phobos โ€” D โ€” @nogc. , , .



Dalam artikel mendatang, kita akan melihat bagaimana mengalokasikan memori tanpa menggunakan GC, dan menggunakannya secara paralel dengan memori dari GC, daripada mengganti @nogcfitur bahasa yang tidak tersedia dalam kode, dan banyak lagi.



Terima kasih kepada Vladimir Panteleev, Guillaume Piolat dan Steven Schveighoffer atas umpan balik mereka yang berharga pada draft artikel ini.




All Articles