C # 'da bulunan farklı veri türlerini açıklamadan önce, C #' ın kesin olarak yazılmış bir dil olduğunu belirtmek önemlidir. Bu, her değişken, sabit, giriş parametresi, dönüş türü ve genel olarak bir değer olarak değerlendirilen her ifadenin bir türü olduğu anlamına gelir.
Her tür, bellek ayırdığında ve geri aldığında tür güvenliğini garantilemek için ortak dil çalışma zamanı (CLR) tarafından kullanılacak üst veri olarak derleyici tarafından yürütülebilir dosyaya gömülecek bilgileri içerir.
Belirli bir türün ne kadar bellek ayırdığını bilmek istiyorsanız, sizeof operatörünü aşağıdaki gibi kullanabilirsiniz:
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}");
}
Çıktı, her değişken tarafından ayrılan bayt sayısını gösterecektir.
int size:4
bool size:1
double size:8
char size:2
Her türle ilgili bilgiler şunlardır:
- Gerekli depolama alanı.
- Maksimum ve minimum değerler. Örneğin, Int32 türü 2147483648 ile 2147483647 arasındaki değerleri kabul eder.
- Devraldığı temel tür.
- Çalışma zamanında değişkenler için belleğin ayrılacağı konum.
- İzin verilen işlem türleri.
Türün içerdiği üyeler (yöntemler, alanlar, olaylar vb.). Örneğin, int türünün tanımını kontrol edersek, aşağıdaki yapı ve üyeleri bulacağız:
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);
...
}
}
Bellek yönetimi
Bir işletim sisteminde birden fazla işlem çalışırken ve RAM miktarı hepsini tutmak için yeterli olmadığında, işletim sistemi sabit diskin parçalarını RAM ile eşler ve verileri sabit diskte depolamaya başlar. İşletim sistemi, isteği gerçekleştirmek için sanal adreslerin karşılık gelen fiziksel adresleriyle eşlendiği belirli tablolardan daha fazlasını kullanacaktır. Bu belleği yönetme özelliğine sanal bellek denir.
Her süreçte, mevcut sanal bellek aşağıdaki 6 bölümde düzenlenmiştir, ancak bu konunun alaka düzeyi için sadece yığın ve yığın üzerine odaklanacağız.
Yığın Yığın
, boyuta bağlı olarak işletim sistemine bağlı bir LIFO (son giren, ilk çıkar) veri yapısıdır (varsayılan olarak, ARM, x86 ve x64 makineleri için Windows'un rezervi 1MB iken, Linux, işletim sistemine bağlı olarak 2MB ila 8MB sürüm).
Belleğin bu bölümü otomatik olarak CPU tarafından yönetilir. Bir işlev yeni bir değişken bildirdiğinde, derleyici yığın üzerindeki boyutu kadar yeni bir bellek bloğu ayırır ve işlev bittiğinde, değişken için bellek bloğu serbest bırakılır.
Yığın
Bu bellek bölgesi, CPU tarafından otomatik olarak yönetilmez ve boyutu yığından daha büyüktür. Yeni anahtar sözcük çağrıldığında, derleyici isteğin boyutuna uyan ilk boş bellek bloğunu aramaya başlar. ve onu bulduğunda, yerleşik C işlevi malloc () kullanılarak ayrılmış olarak işaretlenir ve işaretçiyi o konuma döndürür. Ayrıca, yerleşik C işlevi free () kullanarak bir bellek bloğunu serbest bırakmak da mümkündür. Bu mekanizma bellek parçalanmasına neden olur ve doğru bellek bloğuna erişmek için işaretçiler kullanmak zorundadır, okuma / yazma işlemlerini gerçekleştirmek yığından daha yavaştır.
Özel ve Yerleşik türler
C #, tam sayıları, boolean, metin karakterlerini vb. Temsil eden standart bir yerleşik tür kümesi sağlarken, kendi türlerinizi oluşturmak için struct, sınıf, arabirim ve enum gibi yapıları kullanabilirsiniz.
Struct yapısını kullanan özel bir tür örneği:
struct Point
{
public int X;
public int Y;
};
Değer ve başvuru türleri
C # türünü aşağıdaki kategorilere ayırabiliriz:
- Değer türleri
- Referans türleri
Değer türleri
Değer türleri System.ValueType sınıfından türetilir ve bu türdeki değişkenler, yığıntaki bellek ayırmaları içinde değerlerini içerir. İki değer türü kategorisi struct ve enum'dur.
Aşağıdaki örnek, boole türünün üyesini gösterir. Gördüğünüz gibi, System.ValueType sınıfına açık bir başvuru yoktur, bunun nedeni bu sınıfın struct tarafından miras alınmasıdır.
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);
...
}
}
Referans türleri
Diğer yandan, referans türleri bir değişkende depolanan gerçek verileri içermez, ancak değerin depolandığı yığının bellek adresini içerir. Başvuru türlerinin kategorileri, sınıflar, temsilciler, diziler ve arabirimlerdir.
Çalışma zamanında, bir başvuru türü değişkeni bildirildiğinde, ona new anahtar sözcükleri kullanılarak oluşturulan bir nesne atanıncaya kadar null değerini içerir.
Aşağıdaki örnek, genel tür List'in üyelerini gösterir.
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);
...
}
}
Belirli bir nesnenin bellek adresini bulmak istemeniz durumunda, System.Runtime.InteropServices sınıfı, yönetilmeyen bellekten yönetilen nesnelere erişmek için bir yol sağlar. Aşağıdaki örnekte, bir dizeye bir tutamaç ayırmak için statik GCHandle.Alloc () yöntemini ve ardından adresini almak için AddrOfPinnedObject yöntemini kullanacağız.
string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");
Çıktı olacak
Memory address:39723832
Referanslar
Resmi belgeler: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019