12/08/2018, 14:55

c# - Điều gì xảy ra khi khai báo biến

Vừa qua thì phiên bản Visual Studio 2017 chính thức được release, cùng với đó là phiên bản c# 7.0 , khiến c# cùng với .NET framework ngày càng trở nên mạnh mẽ. Phiên bản c# 7.0 với những tính năng vô cùng mạnh mẽ cho phép code trở nên ngắn và mạch lạc hơn. Nhưng có khi nào với sự phát ...

Vừa qua thì phiên bản Visual Studio 2017 chính thức được release, cùng với đó là phiên bản c# 7.0, khiến c# cùng với .NET framework ngày càng trở nên mạnh mẽ. Phiên bản c# 7.0 với những tính năng vô cùng mạnh mẽ cho phép code trở nên ngắn và mạch lạc hơn. Nhưng có khi nào với sự phát triển mạnh mẽ của ngôn ngữ mà chúng ta vô tình quên đi những khái niệm tuy đơn giản nhưng lại rất quan trọng không? Có thể lắm chứ. Trong bài này mình sẽ cùng tìm hiểu về 6 khái niệm quan trọng trong .NET đó là Stack, heap, value types, reference types, boxing và unboxing.

public void Method1()
{
    int i =4;
    int y = 2;
    class1 cls1 = new class1();
}

Khi chạy Method1() thì thứ tự các biến i, j, cls1 sẽ được lưu ở đâu và giải phóng như thế nào? Có 2 loại bô nhớ đó là ở stack memory và heap memory. Vậy stackheap là gì và khác nhau như thế nào?

Stack and Heap

Stack:

  • Nằm ở bộ nhớ RAM của máy tính như heap
  • Biến tạo ra ở stack sẽ được lưu trực tiếp vào bộ nhớ RAM và truy cập rất nhanh, nhưng có thể dẫn đến hiện tượng overflow (tràn bộ nhớ RAM)
  • Stack vận hành theo hình thức LIFO (Last in first out), nghĩa là vào sau ra trước. Khi ra khỏi scope của hàm thì các biến sẽ tự động được giải phóng.
  • Static memory

Heap:

  • Cũng nằm ở bộ nhớ RAM như stack nhưng trỏ tới virtual memory (ổ cứng) nên truy cập chậm hơn nhưng dung lượng thì giới hạn bởi bộ nhớ ổ cứng nên khá lớn, có thể dẫn đến memory leak (quá bộ nhớ)
  • Không như biến ở stack, biến lưu ở heap không phụ thuộc vào thứ tự vào ra, nó có thể truy cập random vào bất cứ lúc nào. Biến lưu ở heap được giải phóng bằng Garbage collector.
  • Dynamic memory

Dữ liệu lưu ở đâu

  • Khi khai báo i=4 thì i sẽ được đưa vào bộ nhớ stack cùng giá trị là 4
  • Khi khai báo tiếp y=2 thì y sẽ được đưa vào bộ nhớ stack với giá trị là 2, y=2 được đặt trên i=4 vì stack cấu trúc dữ liệu theo LIFO
  • Khi khai báo cls1 thì cls1 sẽ được lưu ở stack, nhưng giá trị của nó thì lại được lưu ở Heap (vì object thường chứa nhiều dữ liệu, heap giới hạn bằng virtual memory nên có thể chưa được dữ liệu lớn)

Khi chạy qua funciton Method1 trên thì i, y sẽ được lưu ở bộ nhớ bộ nhớ stack, còn cls1 sẽ được lưu ở bộ nhớ heap. Khi ra khỏi hàm thì i, j sẽ được giải phòng còn cls1 vẫn còn tồn tại trên heap cho đến khi garbage collector giải phóng.

Value types and reference type

Hay còn được gọi với tên là tham trị và tham chiếu. Hai khái niệm này liên quan đến stack và heap.

  • Value types (tham trị): biến và giá trị đều năm trên stack
  • Reference type (tham chiếu): biến nằm ở stack nhưng giá trị sẽ nằm ở heap, biến ở stack sẽ trỏ đến vị trí của giá trị ở trên heap (reference).

Trong .NET thì biến thuộc kiểu StringObject chính là reference type, còn các biến khác sẽ là value type.

Boxing và Unboxing

public void Method1()
{
    int i = 1;
    object O = i;
    int j = (int) O;
}
  • Ở trên thì i = 1 được lưu ở stack và là i value type.
  • Nhưng khi chạy câu lệnh object O = i thì vì object là kiểu reference type nên giá trị sẽ được lưu ở heap, nên có 1 quá trình lấy giá trị i từ stack đưa vào heap -> boxing.
  • Ở câu lệnh thứ 3 j là kiểu int nên là value type, nhưng mà lấy giá trị từ Oreference type, nên có 1 quá trình lấy giá trị O từ heap về stack -> unboxing

Việc move biến từ kiểu value type sang reference type , thì dữ liệu move từ stack sang heap, quá trình này được gọi là boxing. Ngược lại, việc move biến từ kiểu reference type sang value type, thì dữ liệu move từ heap sang stack, quá trình này được gọi là unboxing.

Để dễ ghi nhớ thì mình cứ nhớ là chuyển từ nhỏ sang lớn (primary type sang object) thì như bỏ 1 viên bi trong cái hộp -> boxing. từ cái lớn chuyển thành cái nhỏ (object thành primary type) thì như mở hộp -> unboxing             </div>
            
            <div class=

0