Stack memory: Quá trình cấp phát và thu hồi trong
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
3 sẽ hoạt động theo kiểu LIFO, nghĩa là dữ liệu nào được cấp phát trước sẽ bị thu hồi sau, tại sao nó lại thế? - Do Stack được sinh ra để phục vụ cho quá trình gọi hàm: ví dụ hàm
public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 6 gọi hàm public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 7, khi đó public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 6 bắt đầu trước public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 7 nhưng lại kết thúc sau, thì các dữ liệu trong hàm public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 6 sẽ được cấp phát trước, sau đó mới tới public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 7; còn khi thu hồi thì ngược lại, dữ liệu trong public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 7 bị thu hồi trước, sau đó tới public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
6
// Allocate sau A()
// Deallocate trước B()
public void B() {
int b = 5;
}
// Allocate trước B()
// Deallocate sau B()
public void A() {
int a = 3;
}
- Thế nên,
public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 3 chỉ chứa dữ liệu phát sinh trong quá trình gọi hàm (aka public class MyClass { }
public record MyRecord { }
void HeapOnly()
{ // Class/Record instance sẽ luôn nằm trên Heap dù có là local variable
var onlyHeapClass = new MyClass();
var onlyHeapRecord = new MyRecord();
} 5), các dữ liệu trong hàm sẽ bị thu hồi sau khi hàm kết thúc. Tuy nhiên, 1 chương trình phải phát sinh dữ liệu nằm ngoài scope của hàm aka public class MyClass { }
public record MyRecord { }
void HeapOnly()
{ // Class/Record instance sẽ luôn nằm trên Heap dù có là local variable
var onlyHeapClass = new MyClass();
var onlyHeapRecord = new MyRecord();
} 6 (không bị thu hồi sau khi hàm kết thúc), từ đó public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4 ra đời - Heap memory: Dữ liệu được cấp phát sẽ không có thứ tự xác định, để truy cập dữ liệu trong
public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4 cần phải thông qua địa chỉ (khi cấp phát xong thì hệ điều hành sẽ trả về địa chỉ này) - Mục đích của Heap là tạo ra các
public class MyClass { }
public record MyRecord { }
void HeapOnly()
{ // Class/Record instance sẽ luôn nằm trên Heap dù có là local variable
var onlyHeapClass = new MyClass();
var onlyHeapRecord = new MyRecord();
} 6, nên dữ liệu trên public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
} 4 sẽ không tự động thu hồi sau khi kết thúc hàm (quá trình thu hồi cần phải được chương trình tự thực hiện, tuy nhiên Garbage collector đã làm hộ chúng ta) public class AllocatedClass { }
public void A() { // Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
Hiệu năng (performance) và kích thước (size) là thứ đáng chú ý giữa
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
3 và
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4! Vậy bài học rút ra là... Hãy tận dụng Stack, và hạn chế Heap nhiều nhất có thể đối với các giá trị tạm thời Value type và Reference typeTrong C# có 2 loại dữ liệu là Value type (managed data types) và Reference type (unmanaged data types), mỗi loại sẽ đại diện cho 1 số kiểu dữ liệu
Reference typeNhư đã nói,
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
7 và
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
9 sẽ luôn nằm trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4 cho dù bạn có khai báo là nó là
public class MyClass { }
public record MyRecord { }
void HeapOnly()
{
// Class/Record instance sẽ luôn nằm trên Heap dù có là local variable
var onlyHeapClass = new MyClass();
var onlyHeapRecord = new MyRecord();
}
5 hay
public class MyClass { }
public record MyRecord { }
void HeapOnly()
{
// Class/Record instance sẽ luôn nằm trên Heap dù có là local variable
var onlyHeapClass = new MyClass();
var onlyHeapRecord = new MyRecord();
}
6
public class MyClass { }
public record MyRecord { }
void HeapOnly()
{
// Class/Record instance sẽ luôn nằm trên Heap dù có là local variable
var onlyHeapClass = new MyClass();
var onlyHeapRecord = new MyRecord();
}
Khi chạy hàm
public class MyClass {
public StackOrHeapStruct AStructFieldWillBeOnHeapToo;
public int IntAlso;
}
public struct StackOrHeapStruct {
}
void HeapOrStackStruct() {
// StackOrHeapStruct là Value type nên nằm trên Stack
var onlyStack = new StackOrHeapStruct();
// Lúc này AStructFieldWillBeOnHeapToo sẽ nằm trên Heap do là 1 field của class
// Dù cho nó có là Value type đi chăng nữa
var myClass = new MyClass {
AStructFieldWillBeOnHeapToo = new StackOrHeapStruct(),
IntAlso = 1
};
}
3 sẽ cho thấy có 2 dữ liệu được cấp phát trên Heap
Value type
Value type (public struct StackOnlyStruct { }
void StackOnly() {
int stackOnlyInt = 5;
AnotherStackOnly(stackOnlyInt, ref stackOnlyInt, false);
}
void AnotherStackOnly(int valueParameterWillBeCopiedIntoTheFunction,
ref int useRefModifierForPassingByReferenceToAvoidCopying, //Pass by reference
in bool useInModifierForPassingByReferenceAndReadonly) //Pass by reference and readonly
{
var stackOnlyStruct = new StackOnlyStruct();
}
9,
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
1,
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
5,
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
- sẽ nằm trên Stack nếu nó là
public class MyClass { }
public record MyRecord { }
void HeapOnly()
{
// Class/Record instance sẽ luôn nằm trên Heap dù có là local variable
var onlyHeapClass = new MyClass();
var onlyHeapRecord = new MyRecord();
}
5 của 1 hàm.
public struct StackOnlyStruct { }
void StackOnly() {
int stackOnlyInt = 5;
AnotherStackOnly(stackOnlyInt, ref stackOnlyInt, false);
}
void AnotherStackOnly(int valueParameterWillBeCopiedIntoTheFunction,
ref int useRefModifierForPassingByReferenceToAvoidCopying, //Pass by reference
in bool useInModifierForPassingByReferenceAndReadonly) //Pass by reference and readonly
{
var stackOnlyStruct = new StackOnlyStruct();
}
Ta có thể thấy khi gọi hàm
public class MyClass {
public StackOrHeapStruct AStructFieldWillBeOnHeapToo;
public int IntAlso;
}
public struct StackOrHeapStruct {
}
void HeapOrStackStruct() {
// StackOrHeapStruct là Value type nên nằm trên Stack
var onlyStack = new StackOrHeapStruct();
// Lúc này AStructFieldWillBeOnHeapToo sẽ nằm trên Heap do là 1 field của class
// Dù cho nó có là Value type đi chăng nữa
var myClass = new MyClass {
AStructFieldWillBeOnHeapToo = new StackOrHeapStruct(),
IntAlso = 1
};
}
9 sẽ không cấp phát trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4 do đều sử dụng các
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
1 (hình dưới cho thấy không có instance nào của
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
2 trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
-
Cần phải chú ý các
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
1 khi được gửi vào các hàm sẽ bị copy vào hàm (tự động tạo 1 biến mới tương tự trong hàm), để tránh quá trình này cần sử dụng ref (Pass by reference) hay in (Tương tự ref nhưng readonly) (quá trình này gọi là
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
5, bài sau mình sẽ hướng dẫn cách hạn chế nó)
Nếu
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
5 có chứa
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
7 thì cũng chỉ có
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
7 đó cấp phát trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4, còn
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
5 vẫn trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
3 (và giữ địa chỉ của class instance nằm trong
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4)
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
Có thể thấy chỉ có
public struct Struct {}
public void StackAllocSpan() {
// Cần phải khai báo kích thước của span
// T phải là Value type
Span<int> notPlayWithHeapIntSpan = stackalloc int[3];
notPlayWithHeapIntSpan[0] = 0;
Span<Struct> notPlayWithHeapStrutSpan = stackalloc Struct[3];
}
3 là trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4 còn
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
2 vẫn trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
3 Value type sẽ trên Heap nếu nó nằm trong 1 Reference typeKhi một
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
1 trở thành field của
public struct StackOnlyStruct { }
void StackOnly() {
int stackOnlyInt = 5;
AnotherStackOnly(stackOnlyInt, ref stackOnlyInt, false);
}
void AnotherStackOnly(int valueParameterWillBeCopiedIntoTheFunction,
ref int useRefModifierForPassingByReferenceToAvoidCopying, //Pass by reference
in bool useInModifierForPassingByReferenceAndReadonly) //Pass by reference and readonly
{
var stackOnlyStruct = new StackOnlyStruct();
}
8 thì nó sẽ nằm trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4, điều này tất nhiên, do nó cần phải "sống" cùng với instance này (không thể bị thu hồi khi kết thúc hàm)
public class MyClass {
public StackOrHeapStruct AStructFieldWillBeOnHeapToo;
public int IntAlso;
}
public struct StackOrHeapStruct {
}
void HeapOrStackStruct() {
// StackOrHeapStruct là Value type nên nằm trên Stack
var onlyStack = new StackOrHeapStruct();
// Lúc này AStructFieldWillBeOnHeapToo sẽ nằm trên Heap do là 1 field của class
// Dù cho nó có là Value type đi chăng nữa
var myClass = new MyClass {
AStructFieldWillBeOnHeapToo = new StackOrHeapStruct(),
IntAlso = 1
};
}
Ta kiểm tra
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4 của chương trình, sẽ thấy không chỉ
public struct Struct {}
public void StackAllocSpan() {
// Cần phải khai báo kích thước của span
// T phải là Value type
Span<int> notPlayWithHeapIntSpan = stackalloc int[3];
notPlayWithHeapIntSpan[0] = 0;
Span<Struct> notPlayWithHeapStrutSpan = stackalloc Struct[3];
}
3 mà còn có
public class MyStruct_1 {
public int MyInt;
public MyClass MyClass;
}
public class MyClass {
public MyStruct_2 MyFieldStruct_2;
}
public class MyStruct_2 {
}
public void MyFunc() {
var myStruct_1 = new MyStruct_1 {
MyInt = 1,
MyClass = new MyClass() {
MyFieldStruct_2 = new MyStruct_2()
}
};
}
2 và
public struct StackOnlyStruct { }
void StackOnly() {
int stackOnlyInt = 5;
AnotherStackOnly(stackOnlyInt, ref stackOnlyInt, false);
}
void AnotherStackOnly(int valueParameterWillBeCopiedIntoTheFunction,
ref int useRefModifierForPassingByReferenceToAvoidCopying, //Pass by reference
in bool useInModifierForPassingByReferenceAndReadonly) //Pass by reference and readonly
{
var stackOnlyStruct = new StackOnlyStruct();
}
9 được cấp phát chung ref struct sẽ đảm bảo 1 struct luôn nằm trên StackThỉnh thoảng bạn sẽ thấy có kiểu khai báo
public class MyStruct_1 {
public int MyInt;
public MyClass MyClass;
}
public class MyClass {
public MyStruct_2 MyFieldStruct_2;
}
public class MyStruct_2 {
}
public void MyFunc() {
var myStruct_1 = new MyStruct_1 {
MyInt = 1,
MyClass = new MyClass() {
MyFieldStruct_2 = new MyStruct_2()
}
};
}
4, thật ra nó không có gì đặc biệt hết, đây chỉ là khai báo đảm bảo
public struct StackOnlyStruct
{
public MyClass AReferenceDoesNotMakeTheStructStayOnHeap;
}
void StackOnly()
{
var stackOnlyStruct = new StackOnlyStruct {
AReferenceDoesNotMakeTheStructStayOnHeap = new MyClass()
};
}
5 này không thể là field của 1
public struct StackOnlyStruct { }
void StackOnly() {
int stackOnlyInt = 5;
AnotherStackOnly(stackOnlyInt, ref stackOnlyInt, false);
}
void AnotherStackOnly(int valueParameterWillBeCopiedIntoTheFunction,
ref int useRefModifierForPassingByReferenceToAvoidCopying, //Pass by reference
in bool useInModifierForPassingByReferenceAndReadonly) //Pass by reference and readonly
{
var stackOnlyStruct = new StackOnlyStruct();
}
8 (để không thể nằm trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4)
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
Đoạn code bên trên sẽ không thể
public class MyStruct_1 {
public int MyInt;
public MyClass MyClass;
}
public class MyClass {
public MyStruct_2 MyFieldStruct_2;
}
public class MyStruct_2 {
}
public void MyFunc() {
var myStruct_1 = new MyStruct_1 {
MyInt = 1,
MyClass = new MyClass() {
MyFieldStruct_2 = new MyStruct_2()
}
};
}
8, do
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
2 là 1 `Kĩ thuật lập trình`0 Cấp phát mảng trên Stack với Span<T>Trước khi kết thúc, mình muốn giới thiệu đến mọi người 1 `Kĩ thuật lập trình`0 là Span<T>, thông thường nó được dùng để trỏ tới 1 mảng trong Heap (tương tự ArraySegment), chúng ta sẽ xem 1 cách dùng hay ho khác nữa
Với kiểu dữ liệu tuần tự (linear sequence), thì bạn sẽ sử dụng `Kĩ thuật lập trình`2 hay `Kĩ thuật lập trình`3, nhưng cả 2 thằng này đều là class (
public struct StackOnlyStruct { }
void StackOnly() {
int stackOnlyInt = 5;
AnotherStackOnly(stackOnlyInt, ref stackOnlyInt, false);
}
void AnotherStackOnly(int valueParameterWillBeCopiedIntoTheFunction,
ref int useRefModifierForPassingByReferenceToAvoidCopying, //Pass by reference
in bool useInModifierForPassingByReferenceAndReadonly) //Pass by reference and readonly
{
var stackOnlyStruct = new StackOnlyStruct();
}
- và sẽ nằm trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4
Nếu muốn sử dụng mảng trên Stack, bạn cần kết hợp `Kĩ thuật lập trình`6 và `Kĩ thuật lập trình`7 (chú ý `Kĩ thuật lập trình`8 phải là
public ref struct StackOnlyStruct {}
public class MyClass {
public StackOnlyStruct AReferenceTypeCanNotEmbedARefStructField;
}
1)
public struct Struct {}
public void StackAllocSpan() {
// Cần phải khai báo kích thước của span
// T phải là Value type
Span<int> notPlayWithHeapIntSpan = stackalloc int[3];
notPlayWithHeapIntSpan[0] = 0;
Span<Struct> notPlayWithHeapStrutSpan = stackalloc Struct[3];
}
Khi gọi hàm
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
00 sẽ không cần cấp phát trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4. Tuy nhiên cần phải chú ý!
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
3 có kích thước nhỏ, khi sử dụng
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
03 thì các phần tử trong
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
03 cũng nằm trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
3 (thay vì chỉ 1 con trỏ tới dữ liệu như mảng thông thường), do đó việc cấp phát Span quá lớn có thể dẫn đến StackOverflow
Sử dụng `Kĩ thuật lập trình`6 sẽ đem lại hiệu năng tốt hơn rất nhiều, tuy nhiên phải lưu ý
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
07 chỉ được sử dụng trong scope của hàm, không đươc
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
08 hay
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
09 nó ra , ngoài ra các
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
10 method cũng không cho phép
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
03 Kết luậnVậy bạn đã có câu trả lời cho câu hỏi ban đầu rồi đúng không?
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
12 sẽ luôn trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4, trong khi đó
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
14 sẽ còn tùy vào tình huống sử dụng
Hãy thử làm 1 quiz nho nhỏ để kiểm tra kiến thức nãy giờ nhé!
public class MyStruct_1 {
public int MyInt;
public MyClass MyClass;
}
public class MyClass {
public MyStruct_2 MyFieldStruct_2;
}
public class MyStruct_2 {
}
public void MyFunc() {
var myStruct_1 = new MyStruct_1 {
MyInt = 1,
MyClass = new MyClass() {
MyFieldStruct_2 = new MyStruct_2()
}
};
}
Nếu ta chạy hàm
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
15 thì
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
16,
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
17,
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
18,
public struct Struct {}
public void StackAllocSpan() {
// Cần phải khai báo kích thước của span
// T phải là Value type
Span<int> notPlayWithHeapIntSpan = stackalloc int[3];
notPlayWithHeapIntSpan[0] = 0;
Span<Struct> notPlayWithHeapStrutSpan = stackalloc Struct[3];
}
3 cái nào sẽ nằm trên
public class AllocatedClass { }
public void A() {
// Biến "a" sẽ không bị tự động thu hồi sau khi A() kết thúc
// Quá trình thu hồi sẽ do Garbage collector đảm nhận
var c = new AllocatedClass();
}
4? Vậy là kết thúc bài đầu tiên trong series này. Ở post sau, mình sẽ đề cập đến 1 vấn đề khi sử dụng struct là Defensive copy và cách giải quyết |