Bộ nhớ biến và quản lý bộ nhớ trong Python

Trong bài này, chúng ta sẽ tìm hiểu bản chất dữ liệu được lưu trữ mà biến (variable) tham chiếu đến. Sau đó, chúng ta cũng sẽ tìm hiểu về cơ chế quản lý bộ nhớ trong Python. Để làm cơ sở tìm hiểu các kiến thức trong bài này, các bạn nên đọc lại bài Đặc điểm của biến (variable) và hằng (constant) trong Python.

1. Bộ nhớ biến (memory of variable) trong Python

Trong ngôn ngữ C/C++, Java hoặc một số ngôn ngữ khác, chúng ta phải khai báo và khởi tạo giá trị cho biến để sử dụng được biến. Ví dụ, khai báo và khởi tạo giá trị cho biến trong C++:

int a;//khai báo biến
a = 5;//gán giá trị cho biến

Các bạn có thể đọc thêm bài Hiểu rõ về bộ nhớ của biến trong C++ để biết cách lưu trữ dữ liệu cho biến trong C++.

Trong Python, chúng ta chỉ cần gán một giá trị cho tên biến để sử dụng được biến. Ví dụ:

x = 5
name = "Python"
salary =  60.50

1.1. Python xử lý như thế nào khi tạo một biến?

Mọi giá trị dữ liệu trong Python đều được xem xét là một loại đối tượng (object). Mỗi đối tượng này được cấp phát một vùng nhớ riêng biệt. Mỗi giá trị đều được Python tạo một đối tượng để lưu trữ, đại diện cho giá trị đó rồi gán đối tượng đó cho biến. Chúng ta cũng thường gọi là biến tham chiếu đến đối tượng (chứ biến không chứa giá trị).

Ví dụ: Khi chúng ta tạo một biến với câu lệnh x = 5, thì Python xử lý như sau:

Bước 1: Python tạo một đối tượng để đại diện cho giá trị 5 trong bộ nhớ (Python tự xác định kiểu dữ liệu là số nguyên).

Bước 2: Python tạo ra một tên định danh là x (tên biến).

Bước 3: Python tạo ra liên kết giữa biến x với đối tượng 5, được gọi là tham chiếu (reference).

Đối tượng lưu trữ dữ liệu trong Python

1.2. Python xử lý khi thay đổi giá trị của biến

Chúng ta cùng xem ví dụ bên dưới.

x = 5   # It's an integer
x = "amazon" # It's a string
x = 40.25   # It's a float

Trong ví dụ trên, khi thực thi câu lệnh x = 5 thì Python tạo một đối tượng của lớp int để lưu trữ giá trị 5. Sau đó, Python cho x tham chiếu đến đối tượng này.

Khi thực thi câu lệnh x = "amazon", Python tạo một đối tượng của lớp str để lưu trữ giá trị “amazon”. Sau đó, Python cho x tham chiếu đến đối tượng này. Lúc này, Python nhận thấy đối tượng lưu trữ giá trị 5 không còn được tên biến nào tham chiếu đến nữa. Do đó, bộ thu gom rác (Garbage Collection) trong Python sẽ tự động giải phóng vùng nhớ của đối tượng lưu trữ giá trị 5.

Khi thực thi câu lệnh x = 40.25, Python tạo một đối tượng của lớp float để lưu trữ giá trị 40.25. Sau đó, Python cho x tham chiếu đến đối tượng này. Lúc này, Python nhận thấy đối tượng lưu trữ giá trị “amazon” không còn được tên biến nào tham chiếu đến nữa. Do đó, bộ thu gom rác (Garbage Collection) trong Python sẽ tự động giải phóng vùng nhớ của đối tượng lưu trữ giá trị “amazon”.

Thay đổi giá trị của biến trong Python

1.3. Nhiều biến tham chiếu đến cùng một object trong Python

Chúng ta cùng xem ví dụ bên dưới.

x = 5
y = x

Chúng ta thấy biến x tham chiếu đến đối tượng của lớp int lưu trữ giá trị 5. Khi thực thi câu lệnh y = x thì y và x đều tham chiếu đến đối tượng lưu trữ giá trị 5.

Nhiều biến tham chiếu cùng một object trong Python

Chúng ta xem thêm một ví dụ bên dưới.

x = 5
y = x
x = "amazon"

Khi thực thi câu lệnh x = "amazon" thì biến x sẽ tham chiếu đến đối tượng của lớp str lưu trữ giá trị “amazon”. Do đó, x sẽ không tham chiếu đến đối tượng lưu trữ giá trị 5 nữa.

Một biến x tham chiếu các object khác nhau trong Python

1.4. Tìm hiểu về bộ đếm tham chiếu (reference counter) trong Python

Bộ đếm tham chiếu (reference counter) trong Python giúp đếm có bao nhiêu biến đang tham chiếu đến một đối tượng trong chương trình. Một đối tượng trong Python lưu trữ các dữ liệu sau:

  • Kiểu dữ liệu (data type)
  • Giá trị dữ liệu (value)
  • Bộ đếm tham chiếu (reference counter)
  • Các biến tham chiếu tương ứng (references)

Ví dụ:

a = 100  
b = 100
a = 5
b = 7

Khi thực thi dòng 1 và 2, đối tượng lưu trữ giá trị 100 có bảng dữ liệu như sau:

data typeint
value100
reference counter2
referencesa, b

Khi thực thi dòng 3, đối tượng lưu trữ giá trị 100 chỉ còn 1 tham chiếu từ b. Khi thực thi dòng 4 thì đối tượng lưu trữ giá trị 100 không còn tham chiếu nào. Lúc này, bộ thu gom rác (Garbage Collection) trong Python sẽ tự động giải phóng vùng nhớ của đối tượng lưu trữ giá trị 100.

1.5. Chương trình Python minh họa địa chỉ bộ nhớ của biến

a = 100
#Output 2699180379472
print("address of a referred object 100:", id(a))
b = 100
#Output 2699180379472
print("address of b referred object 100:", id(b))
a = 200
#Output 2699180382672
print("address of a referred object 200:", id(a))
b = 500
#Output 2699181414608
print("address of b referred object 500:", id(b))
#Output 2699180379472
print("address of object 100:", id(100))
Kết quả
address of a referred object 100: 2699180379472
address of b referred object 100: 2699180379472
address of a referred object 200: 2699180382672
address of b referred object 500: 2699181414608
address of object 100: 2699180379472
Ví dụ về id của biến trong Python

2. Cơ chế quản lý bộ nhớ trong Python

2.1. Bộ nhớ stack và bộ nhớ heap trong Python

Bộ nhớ cấp phát (memory allocation) cho chương trình Python được chia thành bộ nhớ stackbộ nhớ heap. Bộ nhớ stack lưu trữ các lời gọi hàm, các đối số được truyền vào hàm, các biến tham chiếu. Bộ nhớ heap lưu trữ tất cả các đối tượng trong chương trình Python.

Ví dụ một chương trình Python sau:

def bar(a):
    a = a - 1
    return a
def foo(a):
    a = a * a
    b = bar(a)
    return b
def main():
    x = 2
    y = foo(x)
    print("x = ", x)
    print("y = ", y)
if __name__ == "__main__":
    main()
Kết quả
x =  2
y =  3

Sơ đồ mô tả quá trình lưu trữ dữ liệu của stack và heap trong chương trình Python trên.

Ví dụ bộ nhớ stack và heap trong Python

Tất cả các đối tượng lưu trữ dữ liệu đều được lưu trữ trong bộ nhớ heap. Các lời gọi hàm và tất cả các biến tham chiếu đều được lưu trữ trong bộ nhớ stack. Điều này là do trong Python thì tất cả các biến đều là tham chiếu đến các đối tượng lưu trữ dữ liệu.

Thứ tự lưu trữ dữ liệu trong stack như sau:

(1) Hàm main() sẽ được thực thi đầu tiên và đưa vào stack. Biến x đưa vào stack và tham chiếu đến object lưu giá trị 2.

(2) Hàm main() gọi hàm foo(). Biến a trong hàm foo() được đưa vào stack và tham chiếu đến object lưu giá trị 4.

(3) Hàm foo() gọi hàm bar(). Biến a trong hàm bar() được đưa vào stack và tham chiếu đến object lưu giá trị 3.

(4) Biến b được đưa vào stack và tham chiếu đến object lưu giá trị 3 được trả về bởi hàm bar().

(5) Biến y được đưa vào stack và tham chiếu đến object lưu giá trị 3 được trả về bởi hàm foo().

2.2. Bộ thu gom rác (Garbage Collection) trong Python

Bộ thu gom rác (Garbage Collection – GC) giúp giải phóng bộ nhớ khi không sử dụng để cung cấp cho các đối tượng khác. Quá trình thu gom rác của GC được lập lịch để thực hiện. Sự lập lịch này dựa trên một ngưỡng (threshold) của GC. Xem chương trình bên dưới để hiểu rõ hơn.

# loading gc
import gc
 
# get the current collection
# thresholds as a tuple
print("Garbage collection thresholds:",
                    gc.get_threshold())
Kết quả
Garbage collection thresholds: (700, 10, 10)

GC chia các object thành 3 thế hệ: youngest generation, older generation, oldest generation. Tiêu chí chia các object là dựa vào thời gian tồn tại của các object (hay số lần đã trải qua quá trình gom rác mà object vẫn còn tồn tại).

Youngest generation gồm các object mới được tạo. Khi số lượng object được cấp phát vùng nhớ trừ đi số lượng đối tượng đã bị thu hồi vùng nhớ lớn hơn ngưỡng 700 thì GC sẽ bắt đầu chạy để gom rác các object trong youngest generation. Các ngưỡng còn lại là 10, 10 là để thu gom rác các object older generation, oldest generation.

Tham khảo: pythoneasy, geeksforgeeks.

5/5 - (7 bình chọn)
Bài trước và bài sau trong môn học<< Nhập xuất (input/output) cơ bản trong PythonCấu trúc điều khiển rẽ nhánh if…else trong Python >>
Chia sẻ trên mạng xã hội:

Để lại một bình luận

Lưu ý:

1) Vui lòng bình luận bằng tiếng Việt có dấu.

2) Khuyến khích sử dụng tên thật và địa chỉ email chính xác.

3) Mọi bình luận trái quy định sẽ bị xóa bỏ.