Rò rỉ bộ nhớ RAM và CPU khi làm việc với Javascript
Javascript rất hay nhưng việc lạm dụng nó hoặc code không tối ưu thì rất nguy hiểm bởi vì việc tràn bộ nhớ RAM là có thể xảy ra. nên nếu bạn đang lập trình cho một website và khi chạy thì thấy bị rò rỉ bộ nhớ một cách nghiêm trọng thì rất có thể là do ứng dụng của bạn gây ra.
Bài viết dưới đây sẽ tham khảo bài của ông Volkan, trước đây ông điều hành trang sarmal.com (giờ site đã chết), ông đã viết ra bài này trong quá trình điều hành và sử dụng website của mình.
1. Tại sao lại rò rỉ bộ nhớ?
Vấn đề rò rỉ bộ nhớ không chỉ xuất hiện ở Internet Explorer mà mọi browser như Chrome, Firefox, Netscape, Opera đều xảy ra hiện tượng này, tuy nhiên theo bản thân ông thì IE là ông vua của hiện tượng này.
Không phải chỉ mỗi ông ghét IE mà hầu như mọi lập trình viên trên thế giới đều ghét IE, không phải vì ganh tị mà về tính năng, giao diện của IE rất hạn chế, kém cỏi hơn rất nhiều so với các trình duyệt khác. ở Việt Nam thì sử dụng thông dụng nhất vẫn là Chrome, Firefox và Cốc Cốc (một sản phẩm của VN).
Bài viết này được đăng tại [free tuts .net]
Mỗi trình duyệt đều có một ưu điểm và nhược điểm riêng. Chẳng hạn như Firefox thì tốn rất nhiều RAM cho việc khởi động, nó không tốt cho việc xử lý chuỗi và mảng, còn Opera thì có thể sẽ bị chết nếu bạn viết một tập lệnh DHTML phức tạp đến mức gây nhầm lẫn cho công cụ convert của nó.
Và trong bài viết này ông Volkan sẽ tập trung vào việc phân tích sự rò rỉ bộ nhớ trên trình duyệt IE, và có thể áp dụng vào các trình duyệt khác.
2. Ví dụ rò rỉ bộ nhớ đơn giản
Hãy bắt đầu bằng một ví dụ đơn giản dưới đây, lý do ta insert một đoạn code JS inline.
<html> <head> <script type="text/javascript"> function LeakMemory(){ var parentDiv = document.createElement("<div onclick='foo()'>"); parentDiv.bigString = new Array(1000).join( new Array(2000).join("XXXXX")); } </script> </head> <body> <input type="button" value="Memory Leaking Insert" onclick="LeakMemory()" /> </body> </html>
Đầu tiên đoạn code parentDiv=document.createElement(...);
sẽ tạo một thẻ div
và nó sẽ hoạt động tạm thời trong phạm vi của script đó, tiếp theo parentDiv.bigString=...
gắn một đối tượng có giá trị rất lớn vào thẻ div
. Khi phương thức LeakMemory()
được gọi thì một phần tử DOM sẽ khởi tạo, và gán giá trị rất lớn đó vào thẻ div, sau đó nó sẽ kết thúc mọi thứ vì đây là một hàm nên phạm vi hoạt động của các biến là cục bộ.
Khi bạn chạy thử và soi bộ nhớ thì sẽ thấy lúc chạy chương trình này thì RAM và CPU đã thực sự bị rò rỉ.
3. Ví dụ rò rỉ phức tạp hơn
Nếu bạn cảm thấy việc đó là quá bình thường thì hãy thử chạy chương trình đó 10 lần, 100 lần và trải nghiệm xem thé nào? có thể máy tính của bạn sẽ đơ và buộc phải khởi động nguội đấy. Bây giờ ông Volkan đã tăng việc xử lý của hàm LeakMemory lên 5000 lần vào cùng một thời điểm để xem kết quả thế nào.
<html> <head> <script type="text/javascript"> function LeakMemory(){ for(i = 0; i < 5000; i++){ var parentDiv = document.createElement("<div onClick='foo()'>"); } } </script> </head> <body> <input type="button" value="Memory Leaking Insert" onclick="LeakMemory()" /> </body>
Chạy chương trình này thì bạn sẽ thấy sơ đồ của RAM và CPU như sau:
Nếu bạn thử chạy ứng dụng demo này ở nhiều tab khác nhau thì rất có thể bại sẽ phải khởi động lại trình duyệt, nặng hơn là khởi động lại máy tính, điều này gây phiền toái cho khách hàng khi sử dụng website rất nhiều.
Bây giờ ta thử sửa lại đoạn code đó với việc lặp 5000 lần nhưng chỉ khởi tạo thẻ div thôi, không gán dữ liệu quá lớn vào thì kết quả sẽ như thế nào?
<html> <head> <script type="text/javascript"> function LeakMemory(){ for(i = 0; i < 50000; i++){ var parentDiv = document.createElement("div"); } } </script> </head> <body> <input type="button" value="Memory Leaking Insert" onclick="LeakMemory()" /> </body> </html>
Và dưới đây là biểu đồ bộ nhớ.
Như hình này thì bạn thấy việc rò rỉ bộ nhớ là khoong có, bởi vì sơ đồ hoạt động theo một đường thẳng, còn việc nó cao là do ông đã chạy một số ứng dụng khác => không có sự rò rỉ bộ nhớ trong trường hợp này.
Vậy, chúng ta hãy thay đổi code một cách đơn giản và hạn chết việc lạm dụng quá nhiều JS trên trang để tránh tình trạng tốn tài nguyên của khách hàng khi sử dụng website.