Xu Hướng 3/2023 # Sự Khác Nhau Giữa Bộ Nhớ Stack Và Heap? # Top 6 View | Channuoithuy.edu.vn

Xu Hướng 3/2023 # Sự Khác Nhau Giữa Bộ Nhớ Stack Và Heap? # Top 6 View

Bạn đang xem bài viết Sự Khác Nhau Giữa Bộ Nhớ Stack Và Heap? được cập nhật mới nhất trên website Channuoithuy.edu.vn. Hy vọng những thông tin mà chúng tôi đã chia sẻ là hữu ích với bạn. Nếu nội dung 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.

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 Nhau Giữa Bộ Nhớ Heap Và Bộ Nhớ Stack Trong Lập Trình Là Gì? 2022

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. Sự khác biệt cơ bản nhất giữa hai loại bộ nhớ này đó là 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 hàm, địa chỉ trả về của hàm trong khi bộ nhớ Heap được dùng để lưu trữ vùng nhớ cho các 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++, 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ớ

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).

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ớ.

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.

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.

Vấn đề lỗi xảy ra đối với vùng nhớ:

Bởi vì bộ nhớ Stack cố định nên nếu chương trình bạn sử dụng quá nhiều bộ nhớ vượt quá khả năng lưu trữ của Stack chắc chắn sẽ xảy ra tình trạng tràn bộ nhớ Stack (Stack overflow), các trường hợp xảy ra như bạn khởi tạo quá nhiều biến cục bộ, hàm đệ quy vô hạn,…

Ví dụ về tràn bộ nhớ Stack với hàm đệ quy vô hạn:

Nếu bạn liên tục cấp phát vùng nhớ mà không giải phóng thì sẽ bị lỗi tràn vùng nhớ Heap (Heap overflow).

Nếu bạn khởi tạo một vùng nhớ quá lớn mà vùng nhớ Heap không thể lưu trữ một lần được sẽ bị lỗi khởi tạo vùng nhớ Heap thất bại.

Ví dụ trường hợp khởi tạo vùng nhớ Heap quá lớn:

Khi nào nên sử dụng bộ nhớ Stack và bộ nhớ Heap

Khi bạn không biết chính xác cần bao nhiêu vùng nhớ là đủ để lưu trữ dữ liệu trong khi chương trình đang chạy thì dùng bộ nhớ Heap (ví dụ điển hình là cấp phát động của mảng), còn lại thì sử dụng bộ nhớ Stack.

Hoặc khi dữ liệu quá lớn vượt quá khả năng của Stack thì bạn nên dùng Heap.

8.10 Phân Loại Các Vùng Nhớ (Stack &Amp; Heap …)

Chào các bạn đang theo dõi khóa học lập trình trực tuyến ngôn ngữ C++.

Sau khi tìm hiểu một số khái niệm cơ bản về con trỏ, cấp phát động, … chúng ta đã thấy được dãy địa chỉ bộ nhớ ảo được chia thành nhiều phân vùng khác nhau và được sử dụng cho những mục đích khác nhau. Trong bài học này, mình sẽ cùng các bạn tổng hợp lại chức năng của một số phân vùng trên bộ nhớ ảo.

Code segment

Code segment (text segment) là nơi mà lưu trữ các mã lệnh đã được biên dịch của các chương trình máy tính. Những mã lệnh trong phân vùng này sẽ được chuyển đến CPU xử lý khi cần thiết. Code segment chỉ chịu sự chi phối của hệ điều hành, các tác nhân khác không thể can thiệp trực tiếp đến phân vùng này. Việc đưa các mã lệnh đã được biên dịch của chương trình lên phân vùng code segment là công việc đầu tiên mà hệ điều hành cần làm khi chúng ta chạy chương trình.

Data segment

Data segment (initialized data segment) là phân vùng mà hệ điều hành sử dụng để khởi tạo giá trị cho các biến kiểu static, biến toàn cục (global variable) của các chương trình.

BSS segment

BSS segment (uninitialized data segment) cũng được dùng để lưu trữ các biến kiểu static, biến toàn cục (global variable) nhưng chưa được khởi tạo giá trị cụ thể.

Heap segment

Heap segment (free srote segment) được sử dụng để cấp phát bộ nhớ thông qua kỹ thuật Dynamic memory allocation.

Để sử dụng kỹ thuật cấp phát bộ nhớ động, ngôn ngữ C++ đã hổ trợ sẵn cho chúng ta toán tử new. Ví dụ:

Toán tử new sau khi thực thi thành công sẽ trả về địa chỉ của vùng nhớ được cấp phát trên heap, chúng ta có thể sử dụng con trỏ có kiểu dữ liệu phù hợp để lưu trữ địa chỉ trả về này, và con trỏ cũng là công cụ duy nhất giúp chúng ta có thể xác định được vị trí vùng nhớ được cấp phát là ở đâu, và cũng thông qua con trỏ để chúng ta có thể giải phóng vùng nhớ đã được cấp phát.

Chúng ta không cần biết rõ cơ chế quản lý bộ nhớ Heap như thế nào, mà chỉ cần biết rằng bộ nhớ được cấp phát trên Heap sẽ không tự giải phóng cho đến khi nào toàn bộ chương trình đang chạy kết thúc. Do đó, nếu chương trình có thời gian chạy quá lâu mà không được giải phóng các vùng nhớ một cách hợp lý, điều này sẽ làm ảnh hưởng đến việc cấp phát bộ nhớ động cho các chương trình khác.

Mình có thể kể ra một số ưu điểm và nhược điểm đáng chú ý khi sử dụng phân vùng Heap như sau:

Việc cấp phát bộ nhớ trên Heap chậm hơn các phân vùng khác.

Vùng nhớ đã được cấp phát sẽ vẫn thuộc quyền kiểm soát của chương trình đang chạy cho đến khi chúng được giải phóng, hoặc nhận được tín hiệu kết thúc chương trình.

Vùng nhớ được cấp phát phải được quản lý bởi ít nhất 1 con trỏ.

Toán tử dereference truy xuất đến vùng nhớ chậm hơn các biến thông thường.

Phân vùng Heap có dung lượng lớn nhất, nên chúng ta có thể sử dụng một cách thoải mái hơn các phân vùng khác.

Stack segment

Call Stack (thường được gọi là Stack) được dùng để cấp phát bộ nhớ cho tham số của các hàm (function parameters) và biến cục bộ (local variables). Call Stack được thực hiện theo cấu trúc dữ liệu stack, do đó, trước khi nói về phân vùng Stack trên bộ nhớ ảo mình sẽ trình bày cho các bạn về cấu trúc dữ liệu stack trước.

Stack data structure

Stack là một cơ chế tổ chức dữ liệu. Các bạn cũng từng làm việc với một kiểu tổ chức dữ liệu khá phổ biến là mảng một chiều. Mỗi cấu trúc dữ liệu sẽ tổ chức dữ liệu dưới một cơ chế khác nhau để sử dụng hiệu quả trong từng công việc cụ thể. Bây giờ chúng ta xem xét cấu trúc dữ liệu stack.

Những đĩa CD này được đặt chồng lên nhau. Khi nhìn vào chồng đĩa CD này, chúng ta chỉ có thể thực hiện 3 công việc:

(1) Nhìn vào đĩa CD trên cùng của chồng đĩa.(2) Lấy ra một đĩa CD nằm trên cùng.(3) Đặt thêm một đĩa CD lên trên cùng của chồng đĩa.

Do đó, chúng ta có thể nhận thấy ngay việc tổ chức dữ liệu theo cơ chế stack gặp nhiều hạn chế hơn so với tổ chức dữ liệu theo mảng một chiều.

Khi sử dụng mảng một chiều, chúng ta có thể truy cập vào bất kì phần tử nào bên trong mảng bằng cách đưa ra chỉ số của phần tử. Nhưng đối với stack thì không được. Chúng ta chỉ có thể thao tác với phần tử nằm trên cùng (ngoài cùng). Chúng ta thường nói stack hoạt động theo cơ chế “Last-in, first-out”. Có nghĩa là phần tử nào được thêm vào mảng sau cùng thì sẽ được lấy ra đầu tiên.

Ví dụ:

Stack ban đầu của chúng ta là

Thêm vào phần tử có giá trị là 3

Thêm vào phần tử có giá trị 9

Lấy một phần tử ra khỏi stack

Call Stack segment

Call stack segment cũng hoạt động dựa trên cơ chế tổ chức dữ liệu như stack. Khi bắt gặp một dòng lệnh khai báo biến, nếu biến đó là biến cục bộ hoặc tham số hàm, nó sẽ được cấp phát tại địa chỉ lớn nhất hiện tại trên Stack. Khi một biến cục bộ hoặc tham số của hàm ra khỏi phạm vi khối lệnh, nó sẽ được đưa ra khỏi Stack.

Để kiểm chứng điều này, các bạn có thể chạy thử đoạn chương trình sau:

Đoạn chương trình này khai báo lần lượt 5 biến cục bộ liên tiếp nhau. Nếu trong trường hợp tại thời điểm khai báo, chỉ có chương trình này được CPU xử lý, chúng ta sẽ thấy địa chỉ của 5 biến cục bộ này có địa chỉ liên tiếp nhau.

Địa chỉ sau cách địa chỉ trước đó đúng bằng kích thước của kiểu dữ liệu int.

Như vậy, lần lượt biến n1 n2 n3 n4 và n5 được cấp phát tại những địa chỉ tiếp theo (từ thấp đến cao) trên phân vùng Stack, và khi ra khỏi hàm main, lần lượt biến n5 n4 n3 n2 và n1 sẽ bị đưa ra khỏi Stack.

Stack overflow

Phân vùng Stack có kích thước khá hạn chế. Trên hệ điều hành Windows mà mình đang sử dụng, Call Stack chỉ có kích thước khoảng 1MB. Nếu chúng ta cố gắng cho chương trình cấp phát vùng nhớ trên Stack vượt quá kích thước của Stack, chúng ta gọi đó là hiện tượng tràn bộ nhớ phân vùng Stack (Stack overflow).

Một số ưu và nhược điểm có thể nhận thấy khi sử dụng phân vùng Stack

Việc cấp phát bộ nhớ trên Call Stack khá nhanh.

Nhìn vào mã nguồn chương trình, chúng ta có thể biết được thời điểm cấp phát và hủy vùng nhớ của biến trên Stack.

Kích thước vùng nhớ cấp phát trên phân vùng Stack phải được khai báo rõ ràng trước khi biên dịch.

Vùng nhớ trên phân vùng Stack có thể được truy cập trực tiếp thông qua định danh.

Kích thước của phân vùng Stack khá hạn chế.

Tổng kết

Trong bài học này, chúng ta đã cùng tìm hiểu qua một số phân vùng bộ nhớ trên dãy địa chỉ bộ nhớ ảo. Còn một phân vùng nữa thuộc vùng dịa chỉ nhỏ nhất, đứng trước Code segment là phân vùng dành cho hệ điều hành. Vì hệ điều hành cũng là một chương trình (nhưng thuộc về hệ thống) nên nó cũng cần được load lên bộ nhớ ảo như những chương trình thông thường. Điều đặc biệt là phân vùng này ngăn chặn mọi hành vi truy cập từ phía người dùng, do đó mình không đề cập đến trong bài học này.

Hẹn gặp lại các bạn trong bài học tiếp theo trong khóa học lập trình C++ hướng thực hành.

Mọi ý kiến đóng góp hoặc thắc mắc có thể đặt câu hỏi trực tiếp tại diễn đàn

chúng tôi

Sự Khác Nhau Giữa Bộ Bài Tarot, Oracle Và Lenormand

Có một sai lầm phổ biến: Điểm giống và khác nhau giữa các bộ bài Tarot, bộ bài Oracle và bộ bài Lenormand là gì? Những bạn mới bắt đầu học thẻ sẽ cảm thấy khó khăn trong việc lựa chọn. Họ muốn biết loại nào tốt hơn, hoặc tại sao lại có các loại thẻ khác nhau. Nói một cách dễ hiểu, các bộ bài Tarot, Oracle và Lenormand thường được bán cùng nhau trong các cửa hàng nên có thể đoán chúng tương tự nhau.

Trước hết, tôi muốn nhấn mạnh rằng không có hình thức bói toán nào tốt hơn hoặc tệ hơn bất kỳ hình thức nào khác. Chúng đều được in trên thẻ và được sử dụng như nhau (xáo trộn và trải trên bề mặt phẳng), nhưng chúng theo hai phong cách diễn giải khác nhau.

Tôi sử dụng bộ bài Tarot, Oracle và Lenormand, mỗi bộ bài đều có cách sử dụng và ý nghĩa riêng. Tôi tin rằng một khi bạn nhận ra sự khác biệt giữa chúng, bạn sẽ giống tôi, giữ chúng trong hộp công cụ giải thích của bạn và yêu chúng như tôi.

Bài hát Oracle và bài tarot

Tôi có thể tóm tắt sự khác biệt giữa hai yếu tố chính của bộ bài Tarot, Oracle và Lenormand: cấu trúc và mục đích.

Bộ bài Lenormand truyền thống có 52 lá, dựa trên 52 bộ bài và các lá 2, 3, 4 và 5 trong mỗi bộ bài đã bị xóa. Do đó, Lenormand cũng có 4 loại bộ đồ, chẳng hạn như bài tây: câu lạc bộ / ngôi sao năm cánh / đất (rồng); tim / cốc / nước (trái tim); spades / kiếm / không khí (spades); kim cương / đũa phép / lửa (cơ khí ). Ngoài ra, các thẻ còn được phân loại theo nghĩa: khá-trung-bình-kém. Nó cũng có thể được phân loại theo tính chất của lá bài: nhóm chỉ thời gian, chỉ hành động, chỉ tâm trạng, chỉ tính cách.

-Tarot có ngôn ngữ tượng trưng nên mọi hình ảnh, chi tiết trên lá bài đều giúp người đọc xác định, tổng hợp thông tin và giải thích Querent.

Ngược lại, hình ảnh trên lá bài Lenormand không quan trọng lắm, chỉ cần biết tên lá bài là có thể biết được ý nghĩa. Ngay cả khi bạn sử dụng một Lenormand khác, ý nghĩa sẽ không khác. Từ quan điểm hiện đại, một số nhà nghiên cứu của Lenormand cho rằng những hình ảnh trên lá bài cũng mang những ý nghĩa quan trọng, chẳng hạn như hướng nhìn của mắt người. Thẻ sẽ cho chúng ta biết họ quan tâm đến điều gì …

-Một vấn đề thú vị nữa là các lá bài Tarot có cả nghĩa tích cực và tiêu cực, chúng ta có thể đọc các nghĩa khác nhau tùy theo mặt trước hoặc mặt sau của lá bài. Đối với Lenormand, chúng tôi chỉ sử dụng nó để đọc một chiều, không có ý nghĩa ngược lại với Lenormand.

Mỗi lá bài tarot đều có ý nghĩa riêng và có thể đọc độc lập, hoặc khi đặt trong giao tiếp, ý nghĩa của mỗi lá bài sẽ tùy thuộc vào vấn đề trong giao tiếp. Ví dụ, với sự trải bài của cây thánh giá Celtic nổi tiếng, mỗi ô bài có một vấn đề cụ thể, chỉ cần thẻ ở vị trí 1 được chuyển sang vị trí 2, ý nghĩa sẽ thay đổi. Do đó, sử dụng 78 lá bài tarot, có rất nhiều cách để giải thích ý nghĩa của chúng.

Đồng thời, Lenormand sẽ đọc theo cặp (hai thẻ với nhau). Trong các trải nghiệm cổ điển gồm 3, 5, 9 hoặc trải Tableau lớn (sử dụng tất cả 36 thẻ), ý nghĩa của mỗi thẻ không phụ thuộc vào vị trí của nó trong trải. Nghệ thuật của các lá bài Lenormand là kết hợp các lá bài lại với nhau, một trong số này bổ sung ý nghĩa cho lá kia, vì vậy cho đến khi kết thúc trải bài, nhiều ý nghĩa chồng chéo được hình thành.

Do đó, càng nhiều lá bài trong trải, độ khó tăng dần và thông tin càng đầy đủ, chi tiết. Có nhiều cách để đọc số trải Reynolds, chẳng hạn như phương pháp đường chéo, phương pháp nhân bản… Kết hợp nhiều phương pháp với nhau, bạn có thể lấy thêm dữ liệu từ thẻ. .

Cập nhật thông tin chi tiết về Sự Khác Nhau Giữa Bộ Nhớ Stack Và Heap? trên website Channuoithuy.edu.vn. Hy vọng nội dung bài viết sẽ đáp ứng được nhu cầu của bạn, chúng tôi sẽ thường xuyên cập nhật mới nội dung để bạn nhận được thông tin nhanh chóng và chính xác nhất. Chúc bạn một ngày tốt lành!