Bagikan melalui


Tutorial: Mengurangi alokasi memori dengan ref keamanan

Seringkali, penyetelan performa untuk aplikasi .NET melibatkan dua teknik. Pertama, kurangi jumlah dan ukuran alokasi timbunan. Kedua, kurangi seberapa sering data disalin. Visual Studio menyediakan alat hebat yang membantu menganalisis bagaimana aplikasi Anda menggunakan memori. Setelah menentukan tempat aplikasi membuat alokasi yang tidak perlu, Anda membuat perubahan untuk meminimalkan alokasi tersebut. Anda mengonversi class jenis ke struct jenis. Anda menggunakan ref fitur keamanan untuk mempertahankan semantik dan meminimalkan penyalinan tambahan.

Gunakan Visual Studio 17.5 untuk pengalaman terbaik dengan tutorial ini. Alat alokasi objek .NET yang digunakan untuk menganalisis penggunaan memori adalah bagian dari Visual Studio. Anda dapat menggunakan Visual Studio Code dan baris perintah untuk menjalankan aplikasi dan membuat semua perubahan. Namun, Anda tidak akan dapat melihat hasil analisis perubahan Anda.

Aplikasi yang akan Anda gunakan adalah simulasi aplikasi IoT yang memantau beberapa sensor untuk menentukan apakah penyusup telah memasuki galeri rahasia dengan barang berharga. Sensor IoT terus mengirim data yang mengukur campuran Oksigen (O2) dan Karbon Dioksida (CO2) di udara. Mereka juga melaporkan suhu dan kelembaban relatif. Masing-masing nilai ini sedikit berfluktuasi sepanjang waktu. Namun, ketika seseorang memasuki ruangan, perubahan sedikit lebih banyak, dan selalu dalam arah yang sama: Oksigen menurun, Karbon Dioksida meningkat, suhu meningkat, seperti halnya kelembaban relatif. Ketika sensor digabungkan untuk menunjukkan peningkatan, alarm penyusup dipicu.

Dalam tutorial ini, Anda akan menjalankan aplikasi, mengambil pengukuran pada alokasi memori, lalu meningkatkan performa dengan mengurangi jumlah alokasi. Kode sumber tersedia di browser sampel.

Menjelajahi aplikasi pemula

Unduh aplikasi dan jalankan sampel pemula. Aplikasi pemula bekerja dengan benar, tetapi karena mengalokasikan banyak objek kecil dengan setiap siklus pengukuran, performanya perlahan-lahan turun saat berjalan dari waktu ke waktu.

Press <return> to start simulation

Debounced measurements:
    Temp:      67.332
    Humidity:  41.077%
    Oxygen:    21.097%
    CO2 (ppm): 404.906
Average measurements:
    Temp:      67.332
    Humidity:  41.077%
    Oxygen:    21.097%
    CO2 (ppm): 404.906

Debounced measurements:
    Temp:      67.349
    Humidity:  46.605%
    Oxygen:    20.998%
    CO2 (ppm): 408.707
Average measurements:
    Temp:      67.349
    Humidity:  46.605%
    Oxygen:    20.998%
    CO2 (ppm): 408.707

Banyak baris yang dihapus.

Debounced measurements:
    Temp:      67.597
    Humidity:  46.543%
    Oxygen:    19.021%
    CO2 (ppm): 429.149
Average measurements:
    Temp:      67.568
    Humidity:  45.684%
    Oxygen:    19.631%
    CO2 (ppm): 423.498
Current intruders: 3
Calculated intruder risk: High

Debounced measurements:
    Temp:      67.602
    Humidity:  46.835%
    Oxygen:    19.003%
    CO2 (ppm): 429.393
Average measurements:
    Temp:      67.568
    Humidity:  45.684%
    Oxygen:    19.631%
    CO2 (ppm): 423.498
Current intruders: 3
Calculated intruder risk: High

Anda dapat menjelajahi kode untuk mempelajari cara kerja aplikasi. Program utama menjalankan simulasi. Setelah Anda menekan <Enter>, itu membuat ruangan, dan mengumpulkan beberapa data garis besar awal:

Console.WriteLine("Press <return> to start simulation");
Console.ReadLine();
var room = new Room("gallery");
var r = new Random();

int counter = 0;

room.TakeMeasurements(
    m =>
    {
        Console.WriteLine(room.Debounce);
        Console.WriteLine(room.Average);
        Console.WriteLine();
        counter++;
        return counter < 20000;
    });

Setelah data garis besar tersebut dibuat, ia menjalankan simulasi pada ruangan, di mana generator angka acak menentukan apakah penyusup telah memasuki ruangan:

counter = 0;
room.TakeMeasurements(
    m =>
    {
        Console.WriteLine(room.Debounce);
        Console.WriteLine(room.Average);
        room.Intruders += (room.Intruders, r.Next(5)) switch
        {
            ( > 0, 0) => -1,
            ( < 3, 1) => 1,
            _ => 0
        };

        Console.WriteLine($"Current intruders: {room.Intruders}");
        Console.WriteLine($"Calculated intruder risk: {room.RiskStatus}");
        Console.WriteLine();
        counter++;
        return counter < 200000;
    });

Jenis lain berisi pengukuran, pengukuran debounced yang merupakan rata-rata dari 50 pengukuran terakhir, dan rata-rata semua pengukuran yang diambil.

Selanjutnya, jalankan aplikasi menggunakan alat alokasi objek .NET. Pastikan Anda menggunakan Release build, bukan Debug build. Pada menu Debug , buka profiler Performa. Periksa opsi Pelacakan Alokasi Objek .NET, tetapi tidak ada yang lain. Jalankan aplikasi Anda hingga selesai. Profiler mengukur alokasi objek dan laporan tentang alokasi dan siklus pengumpulan sampah. Anda akan melihat grafik yang mirip dengan gambar berikut:

Allocation graph for running the intruder alert app before any optimizations.

Grafik sebelumnya menunjukkan bahwa bekerja untuk meminimalkan alokasi akan memberikan manfaat performa. Anda melihat pola sawtooth di grafik objek langsung. Itu memberi tahu Anda bahwa banyak objek dibuat yang dengan cepat menjadi sampah. Mereka kemudian dikumpulkan, seperti yang ditunjukkan dalam grafik delta objek. Bilah merah ke bawah menunjukkan siklus pengumpulan sampah.

Selanjutnya, lihat tab Alokasi di bawah grafik. Tabel ini memperlihatkan jenis apa yang paling banyak dialokasikan:

Chart that shows which types are allocated most frequently.

Jenis akun System.String untuk alokasi terbanyak. Tugas yang paling penting harus meminimalkan frekuensi alokasi string. Aplikasi ini mencetak banyak output berformat ke konsol terus-menerus. Untuk simulasi ini, kami ingin menyimpan pesan, jadi kami akan berkonsentrasi pada dua baris berikutnya: SensorMeasurement jenisnya, dan jenisnya IntruderRisk .

Klik dua kali pada SensorMeasurement baris. Anda dapat melihat bahwa semua alokasi berlangsung dalam static metode SensorMeasurement.TakeMeasurement. Anda dapat melihat metode dalam cuplikan berikut:

public static SensorMeasurement TakeMeasurement(string room, int intruders)
{
    return new SensorMeasurement
    {
        CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
        O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
        Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
        Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
        Room = room,
        TimeRecorded = DateTime.Now
    };
}

Setiap pengukuran mengalokasikan objek baru SensorMeasurement , yang merupakan class jenis. Setiap SensorMeasurement yang dibuat menyebabkan alokasi timbunan.

Mengubah kelas menjadi struktur

Kode berikut menunjukkan deklarasi awal dari SensorMeasurement:

public class SensorMeasurement
{
    private static readonly Random generator = new Random();

    public static SensorMeasurement TakeMeasurement(string room, int intruders)
    {
        return new SensorMeasurement
        {
            CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
            O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
            Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
            Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
            Room = room,
            TimeRecorded = DateTime.Now
        };
    }

    private const double CO2Concentration = 409.8; // increases with people.
    private const double O2Concentration = 0.2100; // decreases
    private const double TemperatureSetting = 67.5; // increases
    private const double HumiditySetting = 0.4500; // increases

    public required double CO2 { get; init; }
    public required double O2 { get; init; }
    public required double Temperature { get; init; }
    public required double Humidity { get; init; }
    public required string Room { get; init; }
    public required DateTime TimeRecorded { get; init; }

    public override string ToString() => $"""
            Room: {Room} at {TimeRecorded}:
                Temp:      {Temperature:F3}
                Humidity:  {Humidity:P3}
                Oxygen:    {O2:P3}
                CO2 (ppm): {CO2:F3}
            """;
}

Jenis ini awalnya dibuat sebagai class karena berisi banyak double pengukuran. Ini lebih besar dari yang Anda inginkan untuk menyalin di jalur panas. Namun, keputusan itu berarti sejumlah besar alokasi. Ubah jenis dari menjadi classstruct.

Mengubah dari class untuk struct memperkenalkan beberapa kesalahan pengompilasi karena kode asli menggunakan null pemeriksaan referensi di beberapa tempat. Yang pertama ada di DebounceMeasurement kelas , dalam AddMeasurement metode :

public void AddMeasurement(SensorMeasurement datum)
{
    int index = totalMeasurements % debounceSize;
    recentMeasurements[index] = datum;
    totalMeasurements++;
    double sumCO2 = 0;
    double sumO2 = 0;
    double sumTemp = 0;
    double sumHumidity = 0;
    for (int i = 0; i < debounceSize; i++)
    {
        if (recentMeasurements[i] is not null)
        {
            sumCO2 += recentMeasurements[i].CO2;
            sumO2+= recentMeasurements[i].O2;
            sumTemp+= recentMeasurements[i].Temperature;
            sumHumidity += recentMeasurements[i].Humidity;
        }
    }
    O2 = sumO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    CO2 = sumCO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Temperature = sumTemp / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Humidity = sumHumidity / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
}

Jenis berisi DebounceMeasurement array 50 pengukuran. Pembacaan untuk sensor dilaporkan sebagai rata-rata dari 50 pengukuran terakhir. Itu mengurangi kebisingan dalam pembacaan. Sebelum pembacaan 50 lengkap diambil, nilai-nilai ini adalah null. Kode memeriksa referensi untuk null melaporkan rata-rata yang benar pada startup sistem. Setelah mengubah jenis menjadi SensorMeasurement struct, Anda harus menggunakan pengujian yang berbeda. Jenisnya SensorMeasurement mencakup string untuk pengidentifikasi ruangan, sehingga Anda dapat menggunakan pengujian tersebut sebagai gantinya:

if (recentMeasurements[i].Room is not null)

Tiga kesalahan kompilator lainnya semuanya ada dalam metode yang berulang kali mengambil pengukuran di ruangan:

public void TakeMeasurements(Func<SensorMeasurement, bool> MeasurementHandler)
{
    SensorMeasurement? measure = default;
    do {
        measure = SensorMeasurement.TakeMeasurement(Name, Intruders);
        Average.AddMeasurement(measure);
        Debounce.AddMeasurement(measure);
    } while (MeasurementHandler(measure));
}

Dalam metode pemula, variabel lokal untuk SensorMeasurement adalah referensi nullable:

SensorMeasurement? measure = default;

Sekarang setelah SensorMeasurement adalah struct bukan class, yang nullable adalah jenis nilai nullable. Anda dapat mengubah deklarasi menjadi jenis nilai untuk memperbaiki kesalahan pengkompilasi yang tersisa:

SensorMeasurement measure = default;

Sekarang setelah kesalahan kompilator telah diatasi, Anda harus memeriksa kode untuk memastikan semantik tidak berubah. Karena struct jenis diteruskan oleh nilai, modifikasi yang dilakukan pada parameter metode tidak terlihat setelah metode kembali.

Penting

Mengubah jenis dari ke classstruct dapat mengubah semantik program Anda. class Ketika jenis diteruskan ke metode, setiap mutasi yang dibuat dalam metode dibuat ke argumen. struct Ketika jenis diteruskan ke metode, dan mutasi yang dibuat dalam metode dibuat ke salinan argumen. Itu berarti metode apa pun yang memodifikasi argumennya berdasarkan desain harus diperbarui untuk menggunakan ref pengubah pada jenis argumen apa pun yang telah Anda ubah dari menjadi classstruct.

Jenis SensorMeasurement tidak menyertakan metode apa pun yang mengubah status, sehingga tidak menjadi perhatian dalam sampel ini. Anda dapat membuktikan bahwa dengan menambahkan pengubah readonly ke SensorMeasurement struct:

public readonly struct SensorMeasurement

Kompilator memberlakukan readonly sifat SensorMeasurement struktur. Jika inspeksi kode Anda melewatkan beberapa metode yang memodifikasi status, pengkompilasi akan memberi tahu Anda. Aplikasi Anda masih dibangun tanpa kesalahan, jadi jenis ini adalah readonly. Menambahkan pengubah readonly saat Anda mengubah jenis dari ke classstruct dapat membantu Anda menemukan anggota yang memodifikasi status struct.

Hindari membuat salinan

Anda telah menghapus sejumlah besar alokasi yang tidak perlu dari aplikasi Anda. Jenis SensorMeasurement tidak muncul dalam tabel di mana saja.

Sekarang, ia melakukan pekerjaan ekstra menyalin SensorMeasurement struktur setiap kali digunakan sebagai parameter atau nilai pengembalian. Struktur SensorMeasurement berisi empat ganda, DateTime dan string. Struktur itu terukur lebih besar dari referensi. Mari kita tambahkan pengubah ref atau in ke tempat-tempat di mana SensorMeasurement jenis digunakan.

Langkah selanjutnya adalah menemukan metode yang mengembalikan pengukuran, atau mengambil pengukuran sebagai argumen, dan menggunakan referensi jika memungkinkan. Mulailah di SensorMeasurement struct. Metode statis TakeMeasurement membuat dan mengembalikan yang baru SensorMeasurement:

public static SensorMeasurement TakeMeasurement(string room, int intruders)
{
    return new SensorMeasurement
    {
        CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
        O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
        Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
        Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
        Room = room,
        TimeRecorded = DateTime.Now
    };
}

Kita akan membiarkan yang satu ini apa adanya, kembali berdasarkan nilai. Jika Anda mencoba untuk kembali oleh ref, Anda akan mendapatkan kesalahan pengkompilasi. Anda tidak dapat mengembalikan ref ke struktur baru yang dibuat secara lokal dalam metode . Desain struktur yang tidak dapat diubah berarti Anda hanya dapat mengatur nilai pengukuran saat konstruksi. Metode ini harus membuat struktur pengukuran baru.

Mari kita lihat lagi DebounceMeasurement.AddMeasurement. Anda harus menambahkan pengubah in ke measurement parameter:

public void AddMeasurement(in SensorMeasurement datum)
{
    int index = totalMeasurements % debounceSize;
    recentMeasurements[index] = datum;
    totalMeasurements++;
    double sumCO2 = 0;
    double sumO2 = 0;
    double sumTemp = 0;
    double sumHumidity = 0;
    for (int i = 0; i < debounceSize; i++)
    {
        if (recentMeasurements[i].Room is not null)
        {
            sumCO2 += recentMeasurements[i].CO2;
            sumO2+= recentMeasurements[i].O2;
            sumTemp+= recentMeasurements[i].Temperature;
            sumHumidity += recentMeasurements[i].Humidity;
        }
    }
    O2 = sumO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    CO2 = sumCO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Temperature = sumTemp / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Humidity = sumHumidity / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
}

Itu menyimpan satu operasi penyalinan. Parameter in adalah referensi ke salinan yang sudah dibuat oleh pemanggil. Anda juga dapat menyimpan salinan dengan TakeMeasurement metode dalam Room jenis . Metode ini menggambarkan bagaimana pengkompilasi memberikan keamanan ketika Anda meneruskan argumen dengan ref. Metode awal TakeMeasurement dalam Room jenis mengambil argumen dari Func<SensorMeasurement, bool>. Jika Anda mencoba menambahkan pengubah in atau ref ke deklarasi tersebut, pengkompilasi melaporkan kesalahan. Anda tidak dapat meneruskan ref argumen ke ekspresi lambda. Pengkompilasi tidak dapat menjamin bahwa ekspresi yang disebut tidak menyalin referensi. Jika ekspresi lambda menangkap referensi, referensi dapat memiliki masa pakai lebih lama dari nilai yang dirujuknya. Mengaksesnya di luar konteks aman ref-nya akan mengakibatkan kerusakan memori. Aturan ref keselamatan tidak mengizinkannya. Anda dapat mempelajari lebih lanjut dalam gambaran umum fitur keamanan ref.

Mempertahankan semantik

Serangkaian perubahan akhir tidak akan berdampak besar pada performa aplikasi ini karena jenisnya tidak dibuat di jalur panas. Perubahan ini menggambarkan beberapa teknik lain yang akan Anda gunakan dalam penyetelan performa Anda. Mari kita lihat kelas awal Room :

public class Room
{
    public AverageMeasurement Average { get; } = new ();
    public DebounceMeasurement Debounce { get; } = new ();
    public string Name { get; }

    public IntruderRisk RiskStatus
    {
        get
        {
            var CO2Variance = (Debounce.CO2 - Average.CO2) > 10.0 / 4;
            var O2Variance = (Average.O2 - Debounce.O2) > 0.005 / 4.0;
            var TempVariance = (Debounce.Temperature - Average.Temperature) > 0.05 / 4.0;
            var HumidityVariance = (Debounce.Humidity - Average.Humidity) > 0.20 / 4;
            IntruderRisk risk = IntruderRisk.None;
            if (CO2Variance) { risk++; }
            if (O2Variance) { risk++; }
            if (TempVariance) { risk++; }
            if (HumidityVariance) { risk++; }
            return risk;
        }
    }

    public int Intruders { get; set; }

    
    public Room(string name)
    {
        Name = name;
    }

    public void TakeMeasurements(Func<SensorMeasurement, bool> MeasurementHandler)
    {
        SensorMeasurement? measure = default;
        do {
            measure = SensorMeasurement.TakeMeasurement(Name, Intruders);
            Average.AddMeasurement(measure);
            Debounce.AddMeasurement(measure);
        } while (MeasurementHandler(measure));
    }
}

Tipe ini berisi beberapa properti. Beberapa jenis class . Membuat Room objek melibatkan beberapa alokasi. Satu untuk dirinya Room sendiri, dan satu untuk setiap anggota jenis class yang dikandungnya. Anda dapat mengonversi dua properti ini dari class jenis ke struct jenis: DebounceMeasurement dan AverageMeasurement jenis. Mari kita kerjakan transformasi tersebut dengan kedua jenis tersebut.

DebounceMeasurement Ubah jenis dari menjadi classstruct. Itu memperkenalkan kesalahan CS8983: A 'struct' with field initializers must include an explicitly declared constructorkompilator . Anda dapat memperbaikinya dengan menambahkan konstruktor tanpa parameter kosong:

public DebounceMeasurement() { }

Anda dapat mempelajari selengkapnya tentang persyaratan ini di artikel referensi bahasa pada struktur.

Penimpaan Object.ToString() tidak mengubah salah satu nilai struktur. Anda dapat menambahkan pengubah ke deklarasi metode tersebut readonly . Jenisnya DebounceMeasurementdapat diubah, jadi Anda harus berhati-hati bahwa modifikasi tidak memengaruhi salinan yang dibuang. Metode AddMeasurement ini mengubah status objek. Ini dipanggil dari Room kelas , dalam TakeMeasurements metode . Anda ingin perubahan tersebut tetap ada setelah memanggil metode . Anda dapat mengubah Room.Debounce properti untuk mengembalikan referensi ke satu instans jenis DebounceMeasurement :

private DebounceMeasurement debounce = new();
public ref readonly DebounceMeasurement Debounce { get { return ref debounce; } }

Ada beberapa perubahan dalam contoh sebelumnya. Pertama, properti adalah properti readonly yang mengembalikan referensi baca-saja ke instans yang dimiliki oleh ruangan ini. Sekarang didukung oleh bidang yang dideklarasikan yang diinisialisasi ketika Room objek dibuat. Setelah membuat perubahan ini, Anda akan memperbarui implementasi AddMeasurement metode. Ini menggunakan bidang backing privat, debounce, bukan properti Debouncereadonly . Dengan begitu, perubahan terjadi pada instans tunggal yang dibuat selama inisialisasi.

Teknik yang sama bekerja dengan Average properti . Pertama, Anda memodifikasi AverageMeasurement jenis dari ke classstruct, dan menambahkan readonly pengubah pada ToString metode :

namespace IntruderAlert;

public struct AverageMeasurement
{
    private double sumCO2 = 0;
    private double sumO2 = 0;
    private double sumTemperature = 0;
    private double sumHumidity = 0;
    private int totalMeasurements = 0;

    public AverageMeasurement() { }

    public readonly double CO2 => sumCO2 / totalMeasurements;
    public readonly double O2 => sumO2 / totalMeasurements;
    public readonly double Temperature => sumTemperature / totalMeasurements;
    public readonly double Humidity => sumHumidity / totalMeasurements;

    public void AddMeasurement(in SensorMeasurement datum)
    {
        totalMeasurements++;
        sumCO2 += datum.CO2;
        sumO2 += datum.O2;
        sumTemperature += datum.Temperature;
        sumHumidity+= datum.Humidity;
    }

    public readonly override string ToString() => $"""
        Average measurements:
            Temp:      {Temperature:F3}
            Humidity:  {Humidity:P3}
            Oxygen:    {O2:P3}
            CO2 (ppm): {CO2:F3}
        """;
}

Kemudian, Anda memodifikasi Room kelas mengikuti teknik yang sama dengan yang Anda gunakan untuk Debounce properti . Properti Average mengembalikan readonly ref ke bidang privat untuk pengukuran rata-rata. Metode memodifikasi AddMeasurement bidang internal.

private AverageMeasurement average = new();
public  ref readonly AverageMeasurement Average { get { return ref average; } }

Hindari tinju

Ada satu perubahan terakhir untuk meningkatkan performa. Program utamanya adalah mencetak statistik untuk ruangan, termasuk penilaian risiko:

Console.WriteLine($"Current intruders: {room.Intruders}");
Console.WriteLine($"Calculated intruder risk: {room.RiskStatus}");

Panggilan ke kotak yang dihasilkan ToString menghasilkan nilai enum. Anda dapat menghindarinya dengan menulis penimpaan di Room kelas yang memformat string berdasarkan nilai perkiraan risiko:

public override string ToString() =>
    $"Calculated intruder risk: {RiskStatus switch
    {
        IntruderRisk.None => "None",
        IntruderRisk.Low => "Low",
        IntruderRisk.Medium => "Medium",
        IntruderRisk.High => "High",
        IntruderRisk.Extreme => "Extreme",
        _ => "Error!"
    }}, Current intruders: {Intruders.ToString()}";

Kemudian, ubah kode dalam program utama untuk memanggil metode baru ToString ini:

Console.WriteLine(room.ToString());

Jalankan aplikasi menggunakan profiler dan lihat tabel yang diperbarui untuk alokasi.

Allocation graph for running the intruder alert app after modifications.

Anda telah menghapus banyak alokasi, dan memberi aplikasi Anda peningkatan performa.

Menggunakan keamanan ref dalam aplikasi Anda

Teknik ini adalah penyetelan performa tingkat rendah. Mereka dapat meningkatkan performa dalam aplikasi Anda saat diterapkan ke jalur panas, dan ketika Anda telah mengukur dampak sebelum dan sesudah perubahan. Dalam kebanyakan kasus, siklus yang akan Anda ikuti adalah:

  • Mengukur alokasi: Tentukan jenis apa yang paling dialokasikan, dan kapan Anda dapat mengurangi alokasi timbunan.
  • Mengonversi kelas ke struct: Berkali-kali, jenis dapat dikonversi dari menjadi classstruct. Aplikasi Anda menggunakan ruang tumpukan alih-alih membuat alokasi tumpukan.
  • Mempertahankan semantik: Mengonversi ke classstruct dapat memengaruhi semantik untuk parameter dan mengembalikan nilai. Metode apa pun yang memodifikasi parameternya sekarang harus menandai parameter tersebut dengan pengubah ref . Itu memastikan modifikasi dilakukan pada objek yang benar. Demikian pula, jika properti atau nilai pengembalian metode harus dimodifikasi oleh pemanggil, pengembalian tersebut harus ditandai dengan pengubah ref .
  • Hindari salinan: Saat Anda meneruskan struct besar sebagai parameter, Anda dapat menandai parameter dengan pengubah in . Anda dapat meneruskan referensi dalam lebih sedikit byte, dan memastikan bahwa metode tidak mengubah nilai asli. Anda juga dapat mengembalikan nilai dengan readonly ref untuk mengembalikan referensi yang tidak dapat dimodifikasi.

Dengan menggunakan teknik ini, Anda dapat meningkatkan performa di jalur panas kode Anda.