Bài 27-Alias và cơ chế gom rác tự động trong Kotlin-OOP phần 6

[polldaddy poll=9764234]

Như vậy hầu hết các bạn đã học xong hướng đối tượng cài đặt bằng Kotlin, trong bài này Tui sẽ nói thêm về Alias và cơ chế gom rác tự động trong Kotlin.

Alias là khả năng mà tại 1 ô nhớ có nhiều đối tượng cùng trỏ tới (>=2 đối tượng).

Cơ chế gom rác tự động còn gọi là garbage collection, nó tự động thu hồi bộ nhớ khi ô nhớ đó không còn đối tượng nào quan lý.

Hai khái niệm này vô cùng quan trọng, các bạn cần phải đảm bảo hiểu rõ nguộn ngành về nó để có thể kiếm soát vấn đề quản lý bộ nhớ khi thực thi các dự án.

Bây giờ Tui sẽ trình bày chi tiết quá trình tạo Alias và garbage collection trong Kotlin (các ngôn ngữ khác tương tự)

Vì Kotlin chạy trong nền JVM nên cơ chế hoạt động sẽ giống với Java.

Để cho có cảm giác về Alias và cơ chế gom rác tự động, ta tạo một lớp phân số như sau:

[code language=”groovy”]

/**
* Created by cafe on 02/06/2017.
*/
class PhanSo {
var tu:Int=1
var mau:Int=1

constructor(tu: Int, mau: Int) {
this.tu = tu
this.mau = mau
}
}

[/code]

Giả sử chúng ta có 2 đối tượng psA, psB như dưới đây:

psA=PhanSo(1,5)

psB=PhanSo(3,7)

Lúc này trên thanh RAM sẽ có 2 ô nhớ cấp phát cho 2 đối tượng phân số được quản lý bởi 2 biến đối tượng psA và psB (Chú ý là phải tưởng tượng nha các thím, chứ mình làm sao biết ô nhớ nào trên thanh RAM được cấp phát):

Hình trên cho thấy 2 đối tượng psA và psB quản lý 2 ô nhớ độc lập. Tức là psA thao tác trên vùng nhớ A sẽ không ảnh hưởng gì tới psB và ngược lại.

Bây giờ Giả sử ta thực hiện lệnh:

psA=psB

Thì lệnh trên: Ngôn ngữ nói “Phân số A bằng Phân số B”, nhưng hệ thống máy tính sẽ làm việc theo cơ chế “Phân số A trỏ tới vùng nhớ mà phân số B đang quản lý”. Hay nói cách khác “Vùng nhớ B” bây giờ có 2 biến đối tượng cùng trỏ tới(cùng quản lý):Như vậy đã xuất hiện Alias ở “vùng nhớ B”. Lúc này sẽ xảy ra 2 hiện tượng như sau:

  • Tại “vùng nhớ B”, nếu psA thay đổi thông tin sẽ làm cho psB thay đổi thông tin (vì cả 2 đối tượng này cùng quản lý một vùng nhớ)
  • “Vùng nhớ A” không còn đối tượng nào tham chiếu tới, lúc này hệ thống sẽ tự động thu hồi bộ nhớ (hủy vùng nhớ A đã cấp trước đó), cơ chế này gọi là cơ chế gom rác tự động

Hình sau minh họa GC (garbage collection):

Tức là trong hàm main ta có như sau:

[code language=”groovy”]

/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array) {
var psA=PhanSo(1,5)
var psB=PhanSo(3,7)
psA=psB
println(“Tử số của A=”+psA.tu)
}

[/code]

Nếu bạn đã hiểu những gì Tui giải thích ở trên thì: Dòng lệnh số 7 phát sinh ra 2 hiện tượng. Đầu tiên là Alias (psA và psB cùng trỏ tới 1 ô nhớ), Thứ hai là Cơ chế gom rác tự động sẽ tự động thu hồi bộ nhớ cấp cho psA ở dòng 5 (vì lúc này psA đã trỏ qua vùng nhớ của psB).

Khi chạy hàm main ở trên thì kết quả là gì?

Tử số của A=3

Vấn đề là bạn có hiểu vì sao Tử số của A bằng 3 hay không? rõ ràng bên trên Khai báo psA=PhanSo(1,5) thì Tử số của psA là 1 chứ sao là 3 được? hi hi  hi rõ ràng bạn phải hiểu dòng lệnh số 7 đã làm thay đổi điều đó rồi, lúc này psA đã trỏ qua vùng nhớ mà psB đang trỏ. Mà vùng nhớ psB đang trỏ thì tử số bằng mấy? nó bằng 3 chứ gì nữa ==> tử số của psA phải là 3 chứ không phải 1 vì psA đã trỏ qua vùng nhớ của psB rồi…. do you understand?

Tiếp tục nếu giả sử Tui sửa tiếp coding như sau:

[code language=”groovy”]

/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array) {
var psA=PhanSo(1,5)
var psB=PhanSo(3,7)
psA=psB
println(“Tử số của A=”+psA.tu)
psA.tu=113
println(“Tử số của B=”+psB.tu)
}

[/code]

Khi chạy hàm main ở trên thì kết quả là gì?

Tử số của A=3
Tử số của B=113

Bạn có hiểu vì sao Tử số của B=113 không? thật phi lý đúng không? rõ ràng dòng lệnh 9 mình chỉ đổi psA.tu=113, đâu có đổi tử số của phân số B đâu, tại sao tử số của B bị đổi theo A? Nó phải là 113 mới đúng, rất có lý không hề phi lý chút nào. Vì như trên Tui giải thích là vùng nhớ B có psA và psB cùng trỏ tới, do đó psA đổi cùng làm psB đổi và ngược lại, do đó khi psA.tu=113 tức là psB.tu cũng bằng 113. Các bạn cứ tưởng tượng thế này: Nếu Tui và các bạn cùng sử dụng chung 1 thẻ ATM, một ngày đẹp trời Tui buồn buồn Tui lấy hết sạch tiền trong ATM đó đi Nhậu –> bạn làm gì còn Cắc nào trong ATM đúng không?

Đôi khi trong quá trình thực hiện phần mềm ta có nhu cầu sao chép đối tượng ra (tạo thêm một đối tượng giống y xì đối tượng cũ nhưng nằm ở ô nhớ khác, để ta có thể tự do thay đổi thông tin trên đối tượng sao chép mà không làm ảnh hưởng tới đối tượng gốc). Kotlin hỗ trợ chúng ta hàm clone trong interface Cloneable để sao chép đối tượng:

Ta chỉnh là lớp Phân số như sau:

[code language=”groovy”]

/**
* Created by cafe on 02/06/2017.
*/
class PhanSo:Cloneable {
var tu:Int=1
var mau:Int=1

constructor(tu: Int, mau: Int) {
this.tu = tu
this.mau = mau
}
fun copy():PhanSo
{
var ps:PhanSo=clone() as PhanSo
return ps
}
}

[/code]

Ta thấy lớp Phân số kế thừa từ Cloneable  và Tui có tự bổ sung hàm copy() cho lớp phân số. hàm này đơn thuần là gọi lệnh clone() của Cloneable  để tạo ra 1 phiên bản mới của đối tượng (dữ liệu giống nhau y xì nhưng nằm trên ô nhớ khác nhau).

Trong main ta sửa lại như sau:

[code language=”groovy”]

/**
* Created by cafe on 02/06/2017.
*/
fun main(args: Array) {
var psA=PhanSo(1,5)
var psB=PhanSo(3,7)
psA=psB
println(“Tử số của A=”+psA.tu)
psA.tu=113
println(“Tử số của B=”+psB.tu)
var psC=psA.copy()
psC.tu=114
println(“Tử số của A=”+psA.tu)
println(“Tử số của C=”+psC.tu)
println(“Mẫu số của C=”+psC.mau)
}

[/code]

Bạn thấy dòng lệnh 11 Tui gọi hàm copy và lưu vào biên psC. Chú ý ngay chỗ này nó tạo ra thêm 1 ô nhớ mới và để cho psC quản lý. Tức là psC không liên can gì tới psA và psB (lúc này psA và psB vẫn đang cùng quản lý ô nhớ B).

Như vậy khi chạy đoạn lệnh trên kết quả là gì?

Tử số của A=3
Tử số của B=113
Tử số của A=113
Tử số của C=114
Mẫu số của C=7

Bạn hiểu vì sao ra kết quả ở trên không? Tui chủ ý không giải thích nữa, để những bạn nào không hiểu thì Comment vào bài học này, những bạn hiểu sẽ giải thích cho các bạn. Nhưng Tui rất mong muốn bạn phải tự hiểu.

Như vậy tới đây Tui đã trình bày xong alias và Cơ chế gom rác tự động trong Kotlin. Các bạn chú ý học kỹ, thực hành lại và có gắng hiểu được nó thông qua các ví dụ ở trên nhé. Các bài sau Tui sẽ trình bày về Extension method trong Kotlin rất là hay và rất là mới mẻ

Các bạn có thể tải source code bài này ở đây: http://www.mediafire.com/file/xx1k62gbwk2n7pk/HocGarbageCollection.rar

Hẹn gặp các bạn ở những bài tiếp theo

Chúc các bạn thành công!

Trần Duy Thanh (http://communityuni.com/)

4 thoughts on “Bài 27-Alias và cơ chế gom rác tự động trong Kotlin-OOP phần 6”

  1. Kiến thức hữu ích. Khi học java hay object mọi người thường biết là nó hoạt động là như vậy nhưng ko hiểu rõ cơ chế hoạt động như thế nào trên bộ nhớ,

  2. cám ơn chia sẻ hữu ích của thầy
    thầy cho em hỏi, khi implement interface sẽ phải định nghĩa lại từ đầu body của nó vậy viết body cho nó từ đầu có tác dụng gì ạ?

Leave a Reply