Trước khi giải thích các kiểu dữ liệu khác nhau có sẵn trong C #, điều quan trọng cần đề cập là C # là một ngôn ngữ được đánh máy mạnh. Điều này có nghĩa là mỗi biến, hằng số, tham số đầu vào, kiểu trả về và nói chung, mọi biểu thức đánh giá một giá trị đều có một kiểu.
Mỗi kiểu chứa thông tin sẽ được trình biên dịch nhúng vào tệp thực thi dưới dạng siêu dữ liệu sẽ được thời gian chạy ngôn ngữ chung (CLR) sử dụng để đảm bảo an toàn cho kiểu khi nó cấp phát và lấy lại bộ nhớ.
Nếu bạn muốn biết một loại cụ thể phân bổ bao nhiêu bộ nhớ, bạn có thể sử dụng toán tử sizeof như sau:
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}");
}
Kết quả đầu ra sẽ hiển thị số byte được phân bổ bởi mỗi biến.
int size:4
bool size:1
double size:8
char size:2
Thông tin liên quan đến từng loại là:
- Không gian lưu trữ cần thiết.
- Giá trị lớn nhất và nhỏ nhất. Ví dụ: kiểu Int32 chấp nhận các giá trị từ 2147483648 đến 2147483647.
- Loại cơ sở mà nó kế thừa.
- Vị trí nơi bộ nhớ cho các biến sẽ được cấp phát tại thời điểm chạy.
- Các loại hoạt động được phép.
Các thành viên (phương thức, trường, sự kiện, v.v.) được chứa bởi kiểu. Ví dụ: nếu chúng ta kiểm tra định nghĩa của kiểu int, chúng ta sẽ tìm thấy cấu trúc và các thành viên sau:
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);
...
}
}
Quản lý bộ nhớ
Khi nhiều tiến trình đang chạy trên một hệ điều hành và dung lượng RAM không đủ để chứa tất cả, hệ điều hành sẽ ánh xạ các phần của đĩa cứng với RAM và bắt đầu lưu trữ dữ liệu trong đĩa cứng. Hệ điều hành sẽ sử dụng các bảng cụ thể nơi các địa chỉ ảo được ánh xạ tới các địa chỉ vật lý tương ứng của chúng để thực hiện yêu cầu. Khả năng quản lý bộ nhớ này được gọi là bộ nhớ ảo.
Trong mỗi quy trình, bộ nhớ ảo có sẵn được sắp xếp theo 6 phần sau đây nhưng đối với sự liên quan của chủ đề này, chúng tôi sẽ chỉ tập trung vào ngăn xếp và đống.
Ngăn xếp Ngăn
xếp là cấu trúc dữ liệu LIFO (vào sau cùng, xuất trước), với kích thước phụ thuộc vào hệ điều hành (theo mặc định, đối với máy ARM, x86 và x64 Dự trữ của Windows là 1MB, trong khi Linux dự trữ từ 2MB đến 8MB tùy thuộc vào phiên bản).
Phần bộ nhớ này được quản lý tự động bởi CPU. Mỗi khi một hàm khai báo một biến mới, trình biên dịch sẽ cấp phát một khối bộ nhớ mới lớn bằng kích thước của nó trên ngăn xếp và khi hàm kết thúc, khối bộ nhớ cho biến sẽ được phân bổ.
Heap
Vùng bộ nhớ này không được quản lý tự động bởi CPU và kích thước của nó lớn hơn ngăn xếp. Khi từ khóa mới được gọi, trình biên dịch bắt đầu tìm kiếm khối bộ nhớ trống đầu tiên phù hợp với kích thước của yêu cầu. và khi tìm thấy nó, nó được đánh dấu là dành riêng bằng cách sử dụng hàm malloc () tích hợp trong C và trả về con trỏ đến vị trí đó. Cũng có thể phân bổ khối bộ nhớ bằng cách sử dụng hàm C tích hợp free (). Cơ chế này gây ra sự phân mảnh bộ nhớ và phải sử dụng con trỏ để truy cập vào đúng khối bộ nhớ, nó chậm hơn ngăn xếp để thực hiện các thao tác đọc / ghi.
Các kiểu tùy chỉnh và tích hợp
Trong khi C # cung cấp một tập hợp chuẩn các kiểu tích hợp đại diện cho số nguyên, boolean, ký tự văn bản, v.v., Bạn có thể sử dụng các cấu trúc như struct, class, interface và enum để tạo các kiểu của riêng mình.
Một ví dụ về kiểu tùy chỉnh sử dụng cấu trúc struct là:
struct Point
{
public int X;
public int Y;
};
Loại giá trị và tham chiếu
Chúng ta có thể phân loại C # thành các loại sau:
- Các loại giá trị
- Các loại tham chiếu
Các kiểu giá trị Các kiểu
giá trị bắt nguồn từ lớp System.ValueType và các biến thuộc kiểu này chứa các giá trị của chúng trong cấp phát bộ nhớ của chúng trong ngăn xếp. Hai loại giá trị là struct và enum.
Ví dụ sau đây cho thấy thành viên của kiểu boolean. Như bạn có thể thấy, không có tham chiếu rõ ràng nào đến lớp System.ValueType, điều này xảy ra vì lớp này được kế thừa bởi 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);
...
}
}
Các kiểu tham chiếu
Mặt khác, các kiểu tham chiếu không chứa dữ liệu thực được lưu trữ trong một biến, mà là địa chỉ bộ nhớ của heap nơi lưu trữ giá trị. Các danh mục của kiểu tham chiếu là lớp, đại biểu, mảng và giao diện.
Tại thời điểm chạy, khi một biến kiểu tham chiếu được khai báo, nó chứa giá trị null cho đến khi một đối tượng đã được tạo bằng các từ khóa mới được gán cho nó.
Ví dụ sau đây cho thấy các thành viên của danh sách kiểu chung.
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);
...
}
}
Trong trường hợp bạn muốn tìm ra địa chỉ bộ nhớ của một đối tượng cụ thể, lớp System.Runtime.InteropServices cung cấp một cách để truy cập vào các đối tượng được quản lý từ bộ nhớ không được quản lý. Trong ví dụ sau, chúng ta sẽ sử dụng phương thức tĩnh GCHandle.Alloc () để cấp phát một xử lý cho một chuỗi và sau đó phương thức AddrOfPinnedObject để truy xuất địa chỉ của nó.
string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");
Đầu ra sẽ là
Memory address:39723832
Tham khảo Tài liệu
chính thức: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019