Thứ Tư, 10 tháng 4, 2013

Truyền Tham Chiếu Trong Java (Java Pass By Reference)

Để truyền parameter theo kiểu tham chiếu thì tham số được truyền phải thuộc kiểu dữ liệu tham chiếu.
Trong java có 2 loại kiểu dữ liệu: Kiểu cơ bản và kiểu tham chiếu 
- Kiểu cơ bản : Số nguyên, số thực, kí tự , logic
- Kiểu tham chiếu : Kiểu mảng, Kiểu lớp đối tượng Class, Kiểu Interface
Java nó phân định hình thức truyền tham số rõ ràng như sau ( có khác so với C/C++)
Khi bạn truyền tham số mà tham số thuộc kiểu dữ liệu cơ bản thì là truyền tham trị ( tức là hàm, phương thức nhận tham số truyền vào đó nó sẽ tạo 1 bản sao của tham số đó và làm việc trên bản sao chứ không làm việc trên bản gốc), còn truyền các kiểu dữ liệu tham chiếu thì tham số sẽ được truyền theo kiểu tham chiếu ( hàm , phương thức nhận tham số truyền vào sẽ làm việc trực tiếp trên bản gốc của tham số)
Demo code Java

PHP Code:
public class PassReference
{
private int number;
public PassReference()
{
number=0;
}
public static void swap(PassReference a,PassReference b)
{
int tg=a.number;
a.number=b.number;
b.number=tg;
}
public int getNumber()
{
return number;
}
public void setNumber(int value)
{
number=value;
}
public static void swapNumber(int a,int b)
{
int tg=a;
a=b;
b=tg;
}
public static void main(String[] args)
{
int a=10;
int b=15;PassReference x=new PassReference();
PassReference y=new PassReference();
x.setNumber(10);
y.setNumber(15);

System.out.println("Truoc khi thuc hien method swap");
System.out.println("x = "+x.getNumber()+" y = "+y.getNumber());
swap(x,y);
System.out.println("Sau khi thuc hien method swap");
System.out.println("x = "+x.getNumber()+" y = "+y.getNumber());

System.out.println("Truoc khi thuc hien method swapNumber");
System.out.println("So a = "+a+" So b = "+b);
swapNumber(a,b);
System.out.println("Sau khi thuc hien method swapNumber");
System.out.println("So a = "+a+" So b = "+b);
}
}

Kết quả mình đã chạy

Mã:
Truoc khi thuc hien method swap
x = 10 y = 15
Sau khi thuc hien method swap
x = 15 y = 10
Truoc khi thuc hien method swapNumber
So a = 10 So b = 15
Sau khi thuc hien method swapNumber
So a = 10 So b = 15

1 – Tham Chiếu:

- Tham chiếu hay biến tham chiếu là một biến lưu giữ địa chỉ của một vùng nhớ được khởi tạo trước đó trong bộ nhớ.

- Khi một phép khởi tạo Object a = new Object() thì hệ thống sẽ cấp phát một vùng nhớ cho new Object() và địa chỉ của vùng nhớ đó sẽ đc biến a lưu trữ.

- Biến tham chiếu được lưu trữ trong stack và vùng nhớ đc cấp phát thì được lưu trong heap của hệ thống

Ví dụ minh hoạ:

    

 

- Một vùng nhớ có thể có một hay nhiều biến tham chiếu tới nó (Nếu vùng nhớ không có biến nào tham chiếu tới nó thì hệ thống thường sẽ quyết định giải phòng vùng nhớ đó theo một chu kỳ nhất định – sẽ bàn kỹ bên dưới).

- Lưu ý: Phép so sánh == trong java đối với 2 đối tượng là phép so sánh địa chỉ mà 2 đối tượng đó lưu trữ.

Ví dụ:

String x = “a”; String y = “a”;

thì phép so sánh (x == y) sẽ trả về false vì ở đây là so sánh địa chỉ của 2 vùng nhớ có giá trị giống nhau là “a”. Phép so sánh chỉ trả về true khi x và y cùng tham chiếu tới 1 vùng nhớ được cấp phát.

Chỉ có x.equals(y) mới là phép so sánh giá trị chuỗi, và ở đây trả về là true.

2 – Các loại tham chiếu:

Để đảm bảo việc sử dụng bộ nhớ hiệu quả (được cấp phát và giải phóng khi cần thiết), mỗi hệ thống có một cơ chế dọn rác các vùng nhớ không bao giờ được dùng đến nữa. Như đã nói ở trên, thông thường những vùng nhớ không có biến nào tham chiếu tới thì hệ thống sẽ đánh dấu nó là vô dụng và sẽ release nó theo một chu kỳ nhất định. Dựa vào cơ chế này, trong java chia ra 4 loại tham chiếu: Strong preference, Weak preference, Soft preference and Phantom preference.

1. Strong Preference:

Đây là loại tham chiếu mà ta dùng thường nhất với kiểu phép gán =

Đối với Strong Preference là một liên kết mạnh mẽ, bất kỳ vùng nhớ nào vẫn còn có 1 Strong Preference lưu trữ địa chỉ của nó (hay tham chiếu tới nó) đều được coi là vùng nhớ cần thiết (hệ thống sẽ không tự thể giải phóng vùng nhớ này với bất kỳ hình thức nào).

Như vậy ta đặt câu hỏi hệ thống làm sao có thể phát hiện ra vùng nhớ nào là vùng nhớ không được dùng nữa ?

Garbage Collector:

Quá trình tìm ra các vùng nhớ không còn tham chiếu là một quá trình dánh dấu được đệ quy từ root – được gọi là Garbage Collector (viết tắt GC).

GC sẽ đi từ root để phát hiện ra các vùng nhớ đc tham chiếu từ root, và từ những vùng nhớ này hệ thống lại đi tìm những vùng nhớ khác đc tham chiếu tới vùng nhớ này… cứ thế hệ thống sẽ đánh dấu được các vùng nhớ mà mình có thể đi qua (reachable) theo hình cây.

Khi quá trình đệ quy kết thúc, những vùng nhớ không được hệ thống đánh dấu là đã đi qua (unreachable) sẽ bị xem là vùng nhớ vô dụng và sẽ được giải phóng bởi GC.

Để thực hiện quá trình đệ quy này, hệ thống phải trả giá một độ phức tạp nhất định tuỳ theo số lượng vùng nhớ đã được cấp phát. Do đó mà hệ thống không thể lúc nào cũng kiểm tra vùng nhớ cần giải phóng mà nó thực hiện theo một chu kỳ nhất định. Điều này nhằm giảm tải được độ phức tạp khi phải đệ quy nhiều lần và nâng cao performance của hệ thống.

Hãy xem ví dụ của quá trình này dưới đây:

Nếu bạn thử thực hiện đệ quy bằng tay theo hình trên sẽ thấy rằng các vùng nhớ 2, 4, 11, 12 là những vùng nhớ không thể nào có liên kết với root. Những vùng nhớ này sẽ được đánh dấu là vùng nhớ vô dụng và sẽ được dọn dẹp trong chu kỳ của GC

Hình dưới đây minh hoạ quá trình hệ thống giải phóng vùng nhớ:

Như vậy với một Strong Preference từ root thì vùng nhớ đó sẽ luôn được giữ mãi.

Nếu việc giữ vùng nhớ đó không được handle và không có chủ đích thì đây là một trong những nguyên nhân dẫn đến tình trạng tràn bộ nhớ Out Of Memory khi có quá nhiều vùng nhớ không bao giờ được dùng đến nhưng vẫn còn Strong Preference.

0 nhận xét:

Đăng nhận xét