Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Tutorial: Mengurangi alokasi memori dengan
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 mengubah jenis class
menjadi jenis struct
. 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. Saat sensor menunjukkan peningkatan secara bersamaan, alarm penyusup akan aktif.
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.
Jelajahi aplikasi awal
Unduh aplikasi dan jalankan sampel awal. 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>
, sistem membuat ruangan dan mengumpulkan beberapa data dasar 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 saja, tidak ada yang lain. Jalankan aplikasi Anda hingga selesai. Profiler mengukur alokasi objek dan melaporkan alokasi serta siklus pengolahan sampah. Anda akan melihat grafik yang mirip dengan gambar berikut:
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:
Jenis System.String mempertanggungjawabkan sebagian besar alokasi. 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: jenis SensorMeasurement
, dan jenis 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 jenis class
. 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 bagian kritis. Namun, keputusan itu berarti sejumlah besar alokasi. Ubah jenis dari class
menjadi struct
.
Mengubah dari class
untuk struct
memperkenalkan beberapa kesalahan pengompilasi karena kode asli menggunakan null
pemeriksaan referensi di beberapa tempat. Yang pertama ada di kelas DebounceMeasurement
, dalam metode AddMeasurement
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 DebounceMeasurement
mengandung array yang terdiri dari 50 pengukuran. Pembacaan untuk sensor dilaporkan sebagai rata-rata dari 50 pengukuran terakhir. Itu mengurangi kebisingan dalam pembacaan. Sebelum 50 pembacaan penuh dilakukan, nilai-nilai ini adalah null
. Kode memeriksa referensi untuk melaporkan rata-rata yang benar pada startup sistem. Setelah mengubah tipe SensorMeasurement
menjadi struct, Anda perlu menggunakan pengujian yang berbeda. Tipe SensorMeasurement
mencakup string
untuk pengidentifikasi ruangan, jadi Anda bisa menggunakan tes tersebut sebagai alternatif.
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 awal, variabel lokal untuk SensorMeasurement
adalah referensi nullable:
SensorMeasurement? measure = default;
Sekarang setelah SensorMeasurement
menjadi struct
bukan class
, tipe nullable-nya adalah tipe 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
tipe dikirim berdasarkan nilai, modifikasi yang dilakukan pada parameter metode tidak terlihat setelah metode selesai.
Penting
Mengubah jenis dari suatu class
menjadi struct
dapat mengubah semantik program Anda. Saat jenis class
diteruskan ke metode, setiap mutasi yang dilakukan dalam metode dilakukan pada argumen. Ketika jenis struct
diteruskan ke metode, dan mutasi yang dilakukan di dalam metode akan dilakukan pada salinan dari argumen. Itu berarti metode apa pun yang dirancang untuk memodifikasi argumennya harus diperbarui dengan menggunakan pengubah ref
pada jenis argumen apa pun yang telah Anda ubah dari class
ke struct
.
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 menerapkan sifat readonly
dari 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
ketika Anda mengubah jenis dari class
ke struct
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, sistem melakukan pekerjaan ekstra dengan menyalin struktur SensorMeasurement
setiap kali digunakan sebagai parameter atau sebagai nilai pengembalian. Struktur SensorMeasurement
berisi empat ganda, DateTime dan string
. Struktur itu jelas lebih besar dibandingkan dengan struktur 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);
}
Ini menghemat satu operasi penyalinan. Parameter in
adalah referensi ke salinan yang sudah dibuat oleh pemanggil. Anda juga dapat menyimpan salinan menggunakan metode TakeMeasurement
dalam jenis Room
. Metode ini menggambarkan bagaimana pengkompilasi memberikan keamanan ketika Anda meneruskan argumen dengan ref
. Metode awal TakeMeasurement
dalam tipe Room
menerima argumen 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 termasuk dalam jenis class
. Membuat Room
objek melibatkan beberapa alokasi. Satu untuk elemen Room
itu sendiri, dan satu untuk setiap anggota tipe 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.
Ubah tipe DebounceMeasurement
dari class
menjadi struct
. Itu menyebabkan kesalahan kompilator CS8983: A 'struct' with field initializers must include an explicitly declared constructor
. 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 nilai apa pun dari struktur. Anda dapat menambahkan pengubah ke deklarasi metode tersebut readonly
. Jenis DebounceMeasurement
ini dapat diubah, jadi Anda perlu berhati-hati agar modifikasi tidak memengaruhi salinan yang sudah dibuang. Metode AddMeasurement
ini mengubah status objek. Ini dipanggil dari kelas Room
, dalam metode TakeMeasurements
. 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 hanya-baca yang mengembalikan referensi hanya-baca ke instans yang dimiliki oleh ruangan ini. Sekarang didukung oleh field yang dideklarasikan, yang diinisialisasi ketika objek Room
dibuat. Setelah membuat perubahan ini, Anda akan memperbarui implementasi AddMeasurement
metode. Ini menggunakan bidang backing privat, debounce
dan bukan properti readonly Debounce
. Dengan begitu, perubahan terjadi pada instans tunggal yang dibuat selama inisialisasi.
Teknik yang sama berfungsi dengan properti Average
. Pertama, Anda memodifikasi AverageMeasurement
jenis dari class
menjadi struct
, dan menambahkan readonly
pengubah pada metode ToString
:
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
class mengikuti teknik yang sama dengan yang Anda gunakan untuk Debounce
property. Properti Average
mengembalikan readonly ref
ke bidang privat untuk pengukuran rata-rata. Metode AddMeasurement
mengarahkan bidang internal.
private AverageMeasurement average = new();
public ref readonly AverageMeasurement Average { get { return ref average; } }
Hindari peninjuan
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.
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.
-
Konversi kelas ke struct: Sering kali, jenis dapat dikonversi dari
class
kestruct
. Aplikasi Anda menggunakan ruang tumpukan alih-alih membuat alokasi tumpukan. -
Mempertahankan semantik: Mengonversi ke
class
struct
dapat memengaruhi semantik untuk parameter dan mengembalikan nilai. Metode apa pun yang memodifikasi parameternya sekarang harus menandai parameter tersebut dengan pengubahref
. 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 pengubahref
. -
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 denganreadonly ref
untuk mengembalikan referensi yang tidak dapat dimodifikasi.
Dengan menggunakan teknik ini, Anda dapat meningkatkan performa di jalur panas kode Anda.