Đề Xuất 2/2023 # Sự Khác Biệt Giữa Stack Và Heap Trong Lập Trình C# # Top 6 Like | Cuocthitainang2010.com

Đề Xuất 2/2023 # Sự Khác Biệt Giữa Stack Và Heap Trong Lập Trình C# # Top 6 Like

Cập nhật nội dung chi tiết về Sự Khác Biệt Giữa Stack Và Heap Trong Lập Trình C# mới nhất trên website Cuocthitainang2010.com. Hy vọng thông tin trong bài viết sẽ đáp ứng được nhu cầu ngoài mong đợi của bạn, chúng tôi sẽ làm việc thường xuyên để cập nhật nội dung mới nhằm giúp bạn nhận được thông tin nhanh chóng và chính xác nhất.

Như các bạn đã biết c# là một ngôn ngữ đa năng, mạnh mẽ và hướng đối tượng. Trong lập trình c# quản lý về cấp phát bộ nhớ và dọn dẹp rác được thực hiện một cách tự động. Tuy nhiên đối với các bạn mới học lập trình c# thì cần hiểu quan tâm đến cơ chế hoạt động của chúng ra sao. Bên cạnh đó những người chưa rõ cũng nên đọc bài viết để hiểu được rõ cách thức hoạt động của một số biến trong lập trình. Bài viết này tôi sẽ khái quát về Stack và Heap các loại biến và giải thích cách hoạt động của chúng.

.Net framwork lưu trữ tất cả các phần tử của mình ở 2 nơi trong bộ nhớ đó là Stack và Heap. Cả Stack và Heap đều có ý nghĩa rất quan trọng trong việc thi hành code. Chúng được đặt trong bộ nhớ điều hành trên máy và chứa những phần của thông tin và chúng ta cần để vận hành.

Sự khác nhau giữa Stack và Heap.

Các bạn hãy hình dùng Stack như một tập hợp các ngăn xếp mà ngăn đầu tiên nằm ở trên cùng. Chúng ta chỉ có thể làm việc được với ngăn xếp trên cùng ấy. Sau khi làm việc với ngăn trên cùng chúng ta phải “vứt” nó đi thì mới làm việc được với ngăn xếp tiếp theo. Còn Heap cũng tương tự như Stack nhưng mục đích sử dụng của Heap là để lưu trữ thông tin chứ không phải lưu lại tất cả các lần thi hành lệnh như stack và tất cả thông tin được lưu trên Heap có thể được truy cập bất kì thời điểm nào. Không có sự phụ thuộc dữ liệu nào được phép truy cập như stack. Nếu Heap là một đống quần áo sạch sẽ trên giường mà bạn có thể thử bất cứ cái nào thì stack như một hộp chứa đồ mà bạn phải lấy cái trước ra rồi mới lấy được cái sau.

Hình ảnh trên không thực sự đúng với những gì diễn ra trong bộ nhớ nhưng có thể cho bạn thấy sự khác biệt giứa Stack và Heap.

Stack có thể tự duy trì, có nghĩa là nó cơ bản có thể quản lý được bộ nhớ của nó, khi “hộp” đầu tiên không được sử dụng nó sẽ được vứt đi. Còn Heap lại khác, chúng ta phải quan tâm đến các dữ liệu dư thừa và việc giữ Heap được “sạch sẽ”.

Cái gì được lưu trong Stack và Heap?

Chúng ta có 4 thứ sẽ được lưu trữ trong Stack và Heap đó là : Tham trị, tham chiếu, con trỏ và các chỉ dẫn.

Các tham trị

Trong C# tất cả những biến được khai báo như sau là tham trị (Năm trong System. ValueType)

bool

byte

char

decimal

double

enum

float

int

long

sbyte

short

struct

uint

ulong

ushort

Tham chiếu

class

interface

delegate

object

string

Con trỏ

Loại thứ 3 được lưu trữ trong bộ nhớ là con trỏ. Con trỏ được quản lý bởi Common Language Nó khác với biến tham chiếu ,biến tham chiếu thì có thể được truy cập bởi một con trỏ. Con trỏ chiếm một vị trí nào đó trong bộ nhớ và sẽ trỏ đến một ví trí khác. Con trỏ có thể truy cập đến mọi thứ bạn lưu trong stack và heap và giá trị của nó có thể là một địa chỉ nhớ hoặc rỗng.

Chỉ dẫn

Tôi sẽ đề cập đến chỉ dẫn ở phần sau của bài viết này.

Làm sao để biết cái gì được làm ở đâu?Chúng ta có 2 quy tắc sau:

Tham chiếu thì luôn được thực hiện trong Heap

Con trỏ và tham trị luôn được thực hiện ở nơi nó được định nghĩa. Điều này khá phức tạp, để hiểu được bạn cần hiểu thêm về cách làm việc của stack.

Stack như tôi đã giới thiệu, dùng để giữ lại các bước thực hiện khi bạn coding. Bạn có thể hình dung nó giống như trạng thái của một thread và mỗi một thread sẽ có một stack riêng cho nó. Khi coding bạn gọi một hàm thì lời gọi hàm và các tham số của hàm sẽ được lưu vào stack. Và chúng ta sẽ thao tác với các biến ở trong hàm nằm trên đầu stack. Các bạn hãy xem ví dụ sau để hiểu rõ hơn.

1

2

3

4

5

6

public

int

AddFive

(

int

pValue

)

{

int

result

;

result

=

pValue

+

5

;

return

result

;

}

Các bạn hãy nhìn vào hình vẽ. Biến kiểu int pValue được nằm trên cùng sau đó mới đến tên hàm AddFive().

Chú ý rẳng hình ảnh chỉ có tính chất minh họa.

Tiếp đến, Thread thi hành method sẽ thực hiện theo nội dung của hàm AddFive() và một trình biên dịch JIT Sẽ được thực hiện nếu đây là lần đầu tiên chúng ta gọi đến nó. Nếu bạn chưa rõ JIT là gì bạn có thể tham khảo bài viết: Phân biệt các khái niệm trong .NET

Và sau khi hàm đó được thực hiện chúng ta cần phải có bộ

nhớ để lưu biến kết quả và đó chính là một nơi trong stack.

Khi hàm kết thúc kết quả sẽ được trả về và được lưu trong biến result.

Và vùng nhớ trong stack sẽ được giải póng bằng cách đưa con trỏ đến một vùng nhớ khác nơi hàm AddFive() bắt đầu và chúng ta sẽ đi xuống hàm tiếp theo trong stack.

Trong ví dụ này, biến “result” là một nơi trong stack. Như ta đã thấy, cứ lúc nào một biến trong method được khai báo thì nó sẽ được đặt vào stack

Tuy nhiên kiểu giá trị cũng được lưu trong Heap. Hãy nhớ quy tắc, Kiểu giá trị luôn đến nơi nó được khai báo? Vậy thì nếu một biến kiểu giá trị được khai báo ngoài hàm nhưng trong một kiểu tham chiếu nó sẽ nằm ở trong kiểu tham chiếu trên Heap.

Chúng ta có lớp class MyInt đây là kiểu tham chiếu vì nó là một class

1

2

3

4

5

6

7

8

9

10

11

12

13

public

class

MyInt

{

public

int

MyValue

;

}

V

à

h

à

m

sau

đấ

y

đượ

c

th

c

hi

n

:

public

MyInt

AddFive

(

int

pValue

)

{

MyInt

result

=

new

MyInt

(

)

;

result

.

MyValue

=

pValue

+

5

;

return

result

;

}

Như tôi đã nói, thread bắt đầu thi hành hàm và những tham số của nó sẽ được đặt vào trong stack của thread đó.

Nó bắt đầu có sự khác biệt với ví dụ trước.

Sau khi hàm AddFive() kết thúc, chúng ta sẽ dọn dẹp ….

không có một con trỏ nào trỏ đến MyInt.

Đây là lúc chúng ta cần đến bộ dọn dữ liệu rác . Mỗi lần chương trình của chúng ta gần vượt qua giới hạn bộ nhớ, chúng ta sẽ cần thêm không gian trong heap. Bộ dọn dữ liệu rác sẽ dừng tất cả các thread lại (a FULL STOP), tìm tất cả các đối tượng trong heap mà đang không được truy cập bởi chương trình chính và xóa nó đi. Bộ dọn dữ liệu rác cũng sẽ tổ chức lại các đối tượng để tạo không gian nhớ và điều chỉnh tất cả các con trỏ đến các đối tượng ở cả stack và Heap. Bạn có thể nghĩ rằng đây là một sự cản trở tới quá trình thực hiện chương trình, do đó việc sắp xếp dự liệu trong stack và Heap là rất cần thiết để có một chương trình tối ưu.

Khi chúng ta sử dụng kiểu tham chiếu, chúng ta phải phân chia con trỏ đến kiểu, không phải chỉ quan tâm đến riêng kiểu tham chiếu tuy nhiên khi chúng ta sử dụng kiểu giá trị chúng ta chỉ cần quan tâm đến bản thân kiểu đó. Nghe có vẻ khó hiểu? Hãy nghiên cứu ví dụ sau:

Nếu chúng ta thực thi hàm sau:

1

2

3

4

5

6

7

8

9

public

int

ReturnValue

(

)

{

int

x

=

new

int

(

)

;

x

=

3

;

int

y

=

new

int

(

)

;

y

=

x

;

y

=

4

;

return

x

;

}

Chúng ta sẽ nhận về giá trị 3, khá là đơn giản phải không?

Tuy nhiên nếu chúng ta sử dụng MyInt class từ trước

1

2

3

4

public

class

MyInt

{

public

int

MyValue

;

}

sau đó chúng ta thực hiện method sau:

1

2

3

4

5

6

7

8

9

public

int

ReturnValue2

(

)

{

MyInt

x

=

new

MyInt

(

)

;

x

.

MyValue

=

3

;

MyInt

y

=

new

MyInt

(

)

;

y

=

x

;

y

.

MyValue

=

4

;

return

x

.

MyValue

;

}

Chúng ta sẽ nhận được kết quả là 4.

Tại sao lại như vậy?

ở ví dụ đầu tiên mọi thư như được sắp sẵn như sau:

1

2

3

4

5

6

7

public

int

ReturnValue

(

)

{

int

x

=

3

;

int

y

=

x

;

y

=

4

;

return

x

;

}

ở ví dụ sau chúng ta không nhận về 3 bời vì cả 2 biến x và y đều trỏ đến 2 đối tượng trên Heap.

1

2

3

4

5

6

7

8

9

public

int

ReturnValue2

(

)

{

MyInt

x

;

x

.

MyValue

=

3

;

MyInt

y

;

y

=

x

;

y

.

MyValue

=

4

;

return

x

.

MyValue

;

}

5

/

5

(

10

votes

)

Sự Khác Nhau Giữa Bộ Nhớ Heap Và Bộ Nhớ Stack Trong Lập Trình

Như chúng ta đã biết thì việc Quản lý bộ nhớ đối với một lập trình viên là rất quan trọng.

Mục đích quan trọng của việc quản lý bộ nhớ là cung cấp những cách thức để cấp phát động các ô nhớ cho chương trình khi được yêu cầu và giải phóng các ô nhớ đó khi không cần dùng nữa. Đây là việc rất quan trọng đối với bất kỳ hệ thống máy tính cao cấp nào vì sẽ có nhiều công việc được tiến hành ở mọi thời điểm.

Nhiều phương pháp đã được tìm ra để gia tăng hiệu quả của việc quản lý bộ nhớ. Những hệ thống bộ nhớ ảo giúp tách những địa chỉ ô nhớ đang được dùng ra khỏi những địa chỉ thực, từ đó cho phép chia sẻ công việc và gia tăng lượng RAM một cách hiệu quả nhờ đánh dấu địa chỉ hoặc chuyển đến vùng lưu trữ thứ hai. Chất lượng của việc quản lý bộ nhớ ảo có thể có tác dụng lớn đến hiệu năng làm việc của hệ thống nói chung.

Bộ nhớ Heap và bộ nhớ Stack bản chất đều cùng là vùng nhớ được tạo ra và lưu trữ trong RAM khi chương trình được thực thi.

Bộ nhớ Stack được dùng để lưu trữ các biến cục bộ trong hàm, tham số truyền vào… Truy cập vào bộ nhớ này rất nhanh và được thực thi khi chương trình được biên dịch.

Bộ nhớ Heap được dùng để lưu trữ vùng nhớ cho những biến con trỏ được cấp phát động bởi các hàm malloc – calloc – realloc (trong C) hoặc từ khóa new (trong c++, c#, java,…).

Ví dụ trong ngôn ngữ lập trình C++:

Ngoài ra, còn rất nhiều trọng điểm để so sánh sự khác nhau giữa bộ nhớ Heap và bộ nhớ Stack như :

Kích thước vùng nhớ Stack: kích thước của bộ nhớ Stack là cố định, tùy thuộc vào từng hệ điều hành, ví dụ hệ điều hành Windows là 1 MB, hệ điều hành Linux là 8 MB (lưu ý là con số có thể khác tùy thuộc vào kiến trúc hệ điều hành của bạn). Heap: kích thước của bộ nhớ Heap là không cố định, có thể tăng giảm do đó đáp ứng được nhu cầu lưu trữ dữ liệu của chương trình.

Đặc điểm vùng nhớ Stack: vùng nhớ Stack được quản lý bởi hệ điều hành, dữ liệu được lưu trong Stack sẽ tự động hủy khi hàm thực hiện xong công việc của mình. Heap: Vùng nhớ Heap được quản lý bởi lập trình viên (trong C hoặc C++), dữ liệu trong Heap sẽ không bị hủy khi hàm thực hiện xong, điều đó có nghĩa bạn phải tự tay hủy vùng nhớ bằng câu lệnh free (trong C), và delete hoặc delete [] (trong C++), nếu không sẽ xảy ra hiện tượng rò rỉ bộ nhớ. Ở các ngôn ngữ lập trình bậc cao như .NET, Java, … đã có chế dọn rác tự động (Garbage Collection), bạn không cần phải tự tay hủy vùng nhớ Heap nữa.

Lưu ý: việc tự động dọn vùng nhớ còn tùy thuộc vào trình biên dịch trung gian.

Bạn sử dụng Stack nếu bạn biết chính xác lượng dữ liệu mà bạn phân bổ trước khi biên dịch và dữ liệu không quá lớn. Ngược lại, bạn nên sử dụng Heap…

Note: Trong các ứng dụng đa luồng chạy song song (multithreading), mỗi luồng xử lý (thread) sẽ có vùng nhớ Stack riêng của nó, trong khi tất cả các luồng cùng chia sẻ một vùng nhớ Heap. Sử dụng chung vùng nhớ Heap đồng nghĩa với việc phải đồng bộ hóa để tránh tình trạng xảy ra mâu thuẫn giữa các luồng, cho nên cấp phát vùng nhớ Heap phải cài đặt thêm một số cơ chế do đó thực hiện lâu hơn so với cấp phát vùng nhớ Stack. Cấp phát và hủy vùng nhớ Heap liên tục có thể xảy ra tình trạng phân mảnh bộ nhớ, từ phân mảnh bộ nhớ có thể dẫn đến lỗi cấp phát bộ nhớ thất bại như những mô tả ở trên.

All Rights Reserved

Sự Khác Nhau Giữa Bộ Nhớ Stack Và Heap?

Stack Heap

Vùng nhớ được cấp phát khi chương trình được biên dịch.

Vùng nhớ được cấp phát khi chạy chương trình (run-time).

Vùng nhớ stack được sử dụng cho việc thực thi thread. Khi gọi hàm, các biến cục bộ của hàm được lưu trữ vào block của stack (theo kiểu LIFO). Cho đến khi hàm trả về giá trị, block này sẽ được xóa tự động. Hay nói cách khác, các biến cục bộ được lưu trữ ở vùng nhớ stack và tự động được giải phóng khi kết thúc hàm.

Vùng nhớ heap được dùng cho cấp phát bộ nhớ động (malloc( ), new( )). Vùng nhớ được cấp phát tồn tại đến khi lập trình viên giải phóng vùng nhớ bằng lệnh free( ) hoặc delete.

Kích thước vùng nhớ stack được fix cố định. Chúng ta không thể tăng hoặc giảm kích thước vùng nhớ stack. Nếu không đủ vùng nhớ stack, gây ra stack overflow. Hiện tượng này xảy ra khi nhiều hàm lồng nhau hoặc đệ quy nhiều lần dẫn đến không đủ vùng nhớ.

Khi kích thước vùng nhớ heap không đủ cho yêu cầu malloc( ), new. Hệ điều hành sẽ có cơ chế tăng kích thước vùng nhớ heap.

Ví dụ: Minh họa stack được sử dụng khi gọi hàm

int MAX(int, int); void main( void ) { int a = 5, b = 7; int max = MAX(a, b); printf("nMAX(%d, %d) = %d", a, b, max); getch(); } int MAX(int a, int b) { }

Giải thích:

Các bạn nhìn Call Stack sẽ thấy hàm main( ) gọi hàm MAX( ). Hàm main( ) và MAX( ) được lưu theo quy tắc (LIFO: last in – first out). Khi kết thúc hàm MAX( ), các thông tin lưu trữ hàm MAX( ) bị xóa, stack chỉ lưu trữ thông tin của hàm main( ). Tương tự như vậy, khi kết thúc hàm main( ), stack được xóa hoàn toàn.

Sự Khác Biệt Giữa Class Và Object Trong Lập Trình Hướng Đối Tượng

Lớp và đối tượng là các thành phần cơ bản trong OOP. Thường có sự nhầm lẫn giữa lớp và các đối tượng. Trong phần này, sẽ giải thích về sự khác biệt giữa lớp và đối tượng.

Một lớp là một thực thể xác định cách một đối tượng sẽ hành xử và những gì đối tượng sẽ chứa. Nói cách khác, đó là một kế hoạch chi tiết (blueprint) hoặc một bộ hướng dẫn để xây dựng một loại đối tượng cụ thể.

Cú pháp

Một đối tượng bao gồm các phương thức (method) và thuộc tính (property) để tạo thành một kiểu dữ liệu cụ thể hữu ích. Đối tượng xác định hành vi của lớp. Khi bạn gửi tin nhắn đến một đối tượng, bạn đang yêu cầu đối tượng gọi hoặc thực thi một trong các phương thức của nó.

Dưới góc nhìn của lập trình, một đối tượng có thể là cấu trúc dữ liệu, biến hoặc hàm. Nó có một vị trí bộ nhớ được cấp phát.

ClassName referenceVariable = new ClassName();

là một kế hoạch chi tiết (blueprint) hoặc nguyên mẫu (prototype) gồm các biến và các phương thức (hàm) chung cho tất cả các đối tượng thuộc cùng một loại.

Một đối tượng là thực thể cụ thể của lớp. Các đối tượng phần mềm thường được sử dụng để mô hình hoá các đối tượng trong thế giới thực trong cuộc sống hàng ngày.

Đây là một ví dụ về việc phát triển một hệ thống quản lý thú cưng, đặc biệt dành cho chó. Bạn sẽ cần nhiều thông tin khác nhau về những chú chó như: giống chó, độ tuổi, cân nặng, kích cỡ v.v.

Bạn cần mô hình hóa những sinh vật ngoài đời thực, tức là chó thành các thực thể phần mềm.

Tuy nhiên, câu hỏi đáng giá triệu đô la là, bạn thiết kế phần mềm như thế nào?

Dừng lại ở đây ngay bây giờ! Liệt kê những khác biệt giữa chúng.

Một số khác biệt bạn có thể liệt kê ra có thể là giống, tuổi, kích cỡ, màu sắc, v.v. Nếu bạn nghĩ trong một phút, những khác biệt này cũng là một số đặc điểm chung được chia sẻ bởi những con chó này. Những đặc điểm này (giống, tuổi, kích thước, màu sắc) có thể tạo thành một thành viên dữ liệu cho đối tượng của bạn.

Tiếp theo, liệt kê các hành vi phổ biến của những con chó này như ngủ, ngồi, ăn, v.v … Đây sẽ là những hành động của các đối tượng phần mềm của chúng ta.

Vậy chúng ta đã xác định những điều sau đây:

Bây giờ, đối với các giá trị khác nhau của các thành viên dữ liệu (kích thước giống, tuổi và màu sắc) trong lớp Java, bạn sẽ nhận được các đối tượng chó khác nhau.

Bạn có thể thiết kế bất kỳ chương trình nào bằng cách sử dụng phương pháp OOP này.

Ví dụ: Tạo lớp và đối tượng

Breed is: Maltese Size is:Small Age is:2 color is: white

Trong chương trình trước, chúng ta đang tạo phương thức main() bên trong lớp Dog. Bây giờ, chúng ta định nghĩa phương thức main() trong một lớp khác ( lớp Exceute). Đây là một cách làm tốt hơn so với cách trước.

Breed is: Maltese Size is:Small Age is:2 color is: white

Lớp Java là một thực thể xác định cách một đối tượng sẽ hành xử và nhưng gì đối tượng sẽ chứa Một đối tượng Java là một thành phần độc lập bao gồm các phương thức và thuộc tính để tạo thành một kiểu dữ liệu mới.

Bạn đang đọc nội dung bài viết Sự Khác Biệt Giữa Stack Và Heap Trong Lập Trình C# trên website Cuocthitainang2010.com. Hy vọng một phần nào đó những thông tin mà chúng tôi đã cung cấp là rất hữu ích với bạn. Nếu nội dung bài viết hay, ý nghĩa bạn hãy chia sẻ với bạn bè của mình và luôn theo dõi, ủng hộ chúng tôi để cập nhật những thông tin mới nhất. Chúc bạn một ngày tốt lành!