Sebelum menjelaskan tipe data berbeda yang tersedia di C #, penting untuk menyebutkan bahwa C # adalah bahasa yang diketik dengan kuat. Ini berarti bahwa setiap variabel, konstanta, parameter masukan, tipe kembalian dan secara umum setiap ekspresi yang dievaluasi ke suatu nilai, memiliki tipe.
Setiap tipe berisi informasi yang akan disematkan oleh kompilator ke dalam file yang dapat dieksekusi sebagai metadata yang akan digunakan oleh runtime bahasa umum (CLR) untuk menjamin keamanan tipe ketika mengalokasikan dan mengambil kembali memori.
Jika Anda ingin mengetahui berapa banyak memori yang dialokasikan oleh tipe tertentu, Anda dapat menggunakan ukuran operator sebagai berikut:
static void Main()
{
var size = sizeof(int);
Console.WriteLine($"int size:{size}");
size = sizeof(bool);
Console.WriteLine($"bool size:{size}");
size = sizeof(double);
Console.WriteLine($"double size:{size}");
size = sizeof(char);
Console.WriteLine($"char size:{size}");
}
Keluarannya akan menunjukkan jumlah byte yang dialokasikan oleh setiap variabel.
int size:4
bool size:1
double size:8
char size:2
Informasi yang terkait dengan masing-masing jenis adalah:
- Ruang penyimpanan yang dibutuhkan.
- Nilai maksimum dan minimum. Misalnya, tipe Int32 menerima nilai antara 2147483648 dan 2147483647.
- Jenis dasar yang diwarisi.
- Lokasi di mana memori untuk variabel akan dialokasikan pada waktu proses.
- Jenis operasi yang diizinkan.
Anggota (metode, bidang, acara, dll.) Yang ada dalam tipe. Misalnya, jika kita memeriksa definisi tipe int, kita akan menemukan struct dan anggota berikut:
namespace System
{
[ComVisible(true)]
public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<Int32>, IEquatable<Int32>
{
public const Int32 MaxValue = 2147483647;
public const Int32 MinValue = -2147483648;
public static Int32 Parse(string s, NumberStyles style, IFormatProvider provider);
...
}
}
Manajemen memori
Ketika beberapa proses berjalan pada sistem operasi dan jumlah RAM tidak cukup untuk menampung semuanya, sistem operasi memetakan bagian hard disk dengan RAM dan mulai menyimpan data di hard disk. Sistem operasi akan menggunakan tabel tertentu di mana alamat virtual dipetakan ke alamat fisik koresponden mereka untuk melakukan permintaan. Kemampuan untuk mengatur memori ini disebut memori virtual.
Dalam setiap proses, memori virtual yang tersedia diatur dalam 6 bagian berikut, tetapi untuk relevansi topik ini, kami hanya akan fokus pada tumpukan dan heap.
Tumpukan
Tumpukan adalah struktur data LIFO (masuk terakhir, keluar pertama), dengan ukuran bergantung pada sistem operasi (secara default, untuk mesin ARM, x86 dan x64, Windows mencadangkan 1MB, sedangkan Linux memesan dari 2MB hingga 8MB tergantung pada Versi: kapan).
Bagian memori ini secara otomatis dikelola oleh CPU. Setiap kali suatu fungsi mendeklarasikan variabel baru, kompilator mengalokasikan blok memori baru sebesar ukurannya pada tumpukan, dan ketika fungsi selesai, blok memori untuk variabel tersebut dibatalkan alokasinya.
Tumpukan
Wilayah memori ini tidak dikelola secara otomatis oleh CPU dan ukurannya lebih besar dari tumpukan. Ketika kata kunci baru dipanggil, kompilator mulai mencari blok memori bebas pertama yang sesuai dengan ukuran permintaan. dan ketika menemukannya, itu ditandai sebagai dicadangkan dengan menggunakan fungsi malloc () C bawaan dan mengembalikan penunjuk ke lokasi itu. Mungkin juga untuk membatalkan alokasi blok memori dengan menggunakan fungsi C bawaan free (). Mekanisme ini menyebabkan fragmentasi memori dan harus menggunakan pointer untuk mengakses blok memori yang tepat, ini lebih lambat daripada stack untuk melakukan operasi baca / tulis.
Tipe Khusus dan Bawaan
Meskipun C # menyediakan satu set standar tipe bawaan yang mewakili bilangan bulat, boolean, karakter teks, dan seterusnya, Anda dapat menggunakan konstruksi seperti struct, class, antarmuka, dan enum untuk membuat tipe Anda sendiri.
Contoh tipe kustom menggunakan konstruksi struct adalah:
struct Point
{
public int X;
public int Y;
};
Tipe nilai dan referensi
Kita dapat mengkategorikan tipe C # ke dalam kategori berikut:
- Jenis nilai
- Jenis referensi
Jenis nilai
nilai berasal dari kelas System.ValueType dan variabel tipe ini berisi nilai mereka dalam alokasi memorinya di tumpukan. Dua kategori tipe nilai adalah struct dan enum.
Contoh berikut menunjukkan anggota tipe boolean. Seperti yang Anda lihat, tidak ada referensi eksplisit ke kelas System.ValueType, ini terjadi karena kelas ini diwarisi oleh struct.
namespace System
{
[ComVisible(true)]
public struct Boolean : IComparable, IConvertible, IComparable<Boolean>, IEquatable<Boolean>
{
public static readonly string TrueString;
public static readonly string FalseString;
public static Boolean Parse(string value);
...
}
}
Jenis referensi
Di sisi lain, jenis referensi tidak berisi data aktual yang disimpan dalam variabel, tetapi alamat memori dari heap tempat nilai disimpan. Kategori tipe referensi adalah kelas, delegasi, array, dan antarmuka.
Pada waktu proses, ketika variabel tipe referensi dideklarasikan, itu berisi nilai null hingga objek yang telah dibuat menggunakan kata kunci baru ditugaskan padanya.
Contoh berikut menunjukkan anggota Daftar tipe generik.
namespace System.Collections.Generic
{
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(Generic.Mscorlib_CollectionDebugView<>))]
[DefaultMember("Item")]
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
{
...
public T this[int index] { get; set; }
public int Count { get; }
public int Capacity { get; set; }
public void Add(T item);
public void AddRange(IEnumerable<T> collection);
...
}
}
Jika Anda ingin mengetahui alamat memori objek tertentu, class System.Runtime.InteropServices menyediakan cara untuk mengakses objek yang dikelola dari memori yang tidak dikelola. Dalam contoh berikut, kita akan menggunakan metode statis GCHandle.Alloc () untuk mengalokasikan pegangan ke string dan kemudian metode AddrOfPinnedObject untuk mengambil alamatnya.
string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");
Outputnya adalah
Memory address:39723832
Referensi
Dokumentasi resmi: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019