Hỏi về việc Erase Array và Set Dictionary = Nothing trước khi End Sub (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Quang_Hải

Thành viên gạo cội
Tham gia
21/2/09
Bài viết
6,074
Được thích
8,005
Nghề nghiệp
Làm đủ thứ
Theo mình kiểm tra thì thấy rằng nếu khai báo mảng hoặc Set 1 đối tượng nào đó bên trong 1 Sub, sau khi End Sub thì mảng và đối tượng sẽ bị tự động được xoá khỏi bộ nhớ máy tính.

Giả sử rằng chúng ta có khai báo Dic và Arr1(), Arr2()
Có nhiều anh chị sử dụng câu lệnh: Set Dic = Nothing Erase Arr1, Arr2... với ý nghĩa là giải phóng bộ nhớ máy tính.

Mình cứ bâng khuâng hoài không biết là có thật sự cần thiết hay không. Các anh chị biết vui lòng giải thích giúp mình vấn đề này cũng như chia sẽ cho các bạn khác kinh nghiệm này để tối ưu hoá tốc độ của code
 
Tôi nhớ là đã đọc trong sách Lập trình VBA trong Excel của Phan Tự Hướng thấy có nói về vấn đề này trong mục "vòng đời của biến". Tôi chưa test kỹ nên không dám đưa ra ý kiến.
 
Upvote 0
Theo mình kiểm tra thì thấy rằng nếu khai báo mảng hoặc Set 1 đối tượng nào đó bên trong 1 Sub, sau khi End Sub thì mảng và đối tượng sẽ bị tự động được xoá khỏi bộ nhớ máy tính.

Giả sử rằng chúng ta có khai báo Dic và Arr1(), Arr2()
Có nhiều anh chị sử dụng câu lệnh: Set Dic = Nothing Erase Arr1, Arr2... với ý nghĩa là giải phóng bộ nhớ máy tính.

Mình cứ bâng khuâng hoài không biết là có thật sự cần thiết hay không. Các anh chị biết vui lòng giải thích giúp mình vấn đề này cũng như chia sẽ cho các bạn khác kinh nghiệm này để tối ưu hoá tốc độ của code

Giả sử ta có code 1:
PHP:
Public Dic as Object
Sub Test1
  Set Dic = "gì gì đo"
  ......
  ....
End Sub
Và đoạn code 2
PHP:
Sub Test2
  Dim Dic as Object
  Set Dic = "gì gì đo"
  ......
  ....
End Sub
Đoạn Test1 cần câu lệnh Set Dic = Nothing còn Test2 thì không cần
Nói chung, với các đối tượng được khai báo Public ở đầu code thì cần giải phóng bộ nhớ, còn đối tượng bên trong Sub thì không cần
 
Upvote 0
Theo mình kiểm tra thì thấy rằng nếu khai báo mảng hoặc Set 1 đối tượng nào đó bên trong 1 Sub, sau khi End Sub thì mảng và đối tượng sẽ bị tự động được xoá khỏi bộ nhớ máy tính.

Giả sử rằng chúng ta có khai báo Dic và Arr1(), Arr2()
Có nhiều anh chị sử dụng câu lệnh: Set Dic = Nothing Erase Arr1, Arr2... với ý nghĩa là giải phóng bộ nhớ máy tính.

Mình cứ bâng khuâng hoài không biết là có thật sự cần thiết hay không. Các anh chị biết vui lòng giải thích giúp mình vấn đề này cũng như chia sẽ cho các bạn khác kinh nghiệm này để tối ưu hoá tốc độ của code

Array thì không cần Erase, hay set nothing, vì nó sẽ tự động xóa khi ra khỏi End Sub/Function (tuy nhiên nếu là sub sử dụng ARRAY chiếm bộ lớn cực lớn -thì nếu muốn giải phóng bộ nhớ ngay khi tiếp tục các lệnh khác tiếp trong Sub / Function thì có thể nên dùng )

Còn Dictionary thì không phải là "có thật sự cần thiết hay không" mà là CẦN THIẾT set nothing sau khi sử dụng, vì sao ư, chắc quanghai1969 tiếng anh ngon, xin mời tham khảo các link sau:
http://www.dailydoseofexcel.com/archives/2004/06/07/nothing-keyword/
https://groups.google.com/forum/?fr....dotnet.languages.vb/3pw-TGc9PSo/DJ2HlkEF6hYJ

Có thể hiểu nôm na là: VBA bản chất là xuất phát từ ngôn ngữ VB - một ngôn ngữ OOP (Oriented Object Programing), rộng hơn nữa Excel, office, Windows đều cấu trúc trên nền tảng này, vì thế khi ta dùng Dictionary Object là giống như ta đi cày - nhưng không muốn cày thủ công muốn mượn cái công cụ đa năng nhanh là cái MÁY CÀY từ ông bạn khác (Scripting Dictionary) - dùng xong xuôi thì ta không chỉ phải trả lại nguyên trạng cái máy đó sạch sẽ (không chứa bụi đất gì cả) mà còn phải báo cho ông bạn đó là tôi đã trả và đã dùng xong cái máy đó (hành động này tương đương set nothing đó) -- có người có thể nói khi thoát khỏi sub/function thì VBA đã tự xóa biến (rác) rùi -- hãy xem lại 2 link trên để thấy việc VB xóa rác có hoàn hảo hay không, chính Microsoft khuyến cáo chúng ta CẦN mà khi sử dụng mượn Object khác từ Library,... khác

túm lại, là nếu muốn chuyên nghiệp bài bản và không để rác do mình tạo ra thì nên viết 1 cách bài bản có set nothing - tránh cả việc chỉ sử dụng With ... không khai báo object theo kiểu chụp giật - bạn không mất gì cả khi viết thêm mấy chữ nhưng nó giúp ích cho việc chuyên nghiệp (lần sau mượn MÁY CÀY người ta còn cho mượn - họ không phải bối rối tìm xem nó đang ở đâu, hay máy đang vứt lơ lửng ngoài bờ sông)
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn các anh chị đã chia sẻ. Đọc tới đọc lui cũng thấy mù mờ quá. Thôi quyết định đọc cái này của bác Bill:

Nothing <keyword>

The Nothing keyword is used to disassociate an object variable from an actual object. Use the Set statement to assign Nothing to an object variable. For example:

Set MyObject = Nothing

Several object variables can refer to the same actual object. When Nothing is assigned to an object variable, that variable no longer refers to an actual object.
When several object variables refer to the same object, memory and system resources associated with the object to which the variables refer are released only after all of them have been set to Nothing, either explicitly using Set, or implicitly after the last object variable set to Nothing goes out of scope.

Với tuyên bố này của bác Bill thì chẳng cần Set Nothing gì ráo. Mọi thứ sẽ tự động biến mất.

Kỹ năng tiếng anh của mình chưa đủ tốt nên có thể hiểu sai câu nói của bác Bill, nhưng tạm thời cứ thế này. Sau này giỏi thêm tí nữa sẽ điều chỉnh lại quan điểm.
 
Lần chỉnh sửa cuối:
Upvote 0
Theo tôi nghĩ, dùng những biến thông thường thì có thể bỏ qua việc giải phóng bộ nhớ, còn những dạng biến Oject dù đặt trong Sub/ Function hay ngoài ta cũng nên giải phóng bộ nhớ cho an toàn, nó chỉ mất vài dòng code thôi, nhưng có lẽ là không thừa đâu.

Nhưng với các biến đặt ngoài kiểu Public, khi nào ta dùng nó đến thủ tục cuối cùng thì ta mới giải phóng biến, chứ không thì ẹc ẹc đấy!
 
Upvote 0
Có một điều mình thắc mắc là mặc dù chúng ta dùng:

Set Ojb = Nothing

Erase sArray

Với Dictionary Dic.RemoveAll

v.v...

Hình như là chỉ xóa nội dung chứa trong nó, chứ thực chất không hoàn toàn xóa chính nó.

Phát biểu như vậy có đúng không?
 
Upvote 0
Có một điều mình thắc mắc là mặc dù chúng ta dùng:

Set Ojb = Nothing

Erase sArray

Với Dictionary Dic.RemoveAll

v.v...

Hình như là chỉ xóa nội dung chứa trong nó, chứ thực chất không hoàn toàn xóa chính nó.

Phát biểu như vậy có đúng không?
Thí nghiệm sẽ biết thôi
PHP:
Sub Test1()
  Dim Dic As Object
  Set Dic = CreateObject("Scripting.Dictionary")
  Dic.Add "a", 1
  Dic.Add "b", 2
  Dic.Add "c", 3
  Dic.RemoveAll
  MsgBox Dic Is Nothing
End Sub
PHP:
Sub Test2()
  Dim Dic As Object
  Set Dic = CreateObject("Scripting.Dictionary")
  Dic.Add "a", 1
  Dic.Add "b", 2
  Dic.Add "c", 3
  Set Dic = Nothing
  MsgBox Dic Is Nothing
End Sub
 
Upvote 0
Thí nghiệm sẽ biết thôi
PHP:
Sub Test1()
  Dim Dic As Object
  Set Dic = CreateObject("Scripting.Dictionary")
  Dic.Add "a", 1
  Dic.Add "b", 2
  Dic.Add "c", 3
  Dic.RemoveAll
  MsgBox Dic Is Nothing
End Sub
PHP:
Sub Test2()
  Dim Dic As Object
  Set Dic = CreateObject("Scripting.Dictionary")
  Dic.Add "a", 1
  Dic.Add "b", 2
  Dic.Add "c", 3
  Set Dic = Nothing
  MsgBox Dic Is Nothing
End Sub

Với mảng thấy thường dùng Erase, thế nhưng mảng không Set, vậy làm sao cho nó Set mảng Nothing được? Nhưng Range thì lại được!
 
Upvote 0
Với mảng thấy thường dùng Erase, thế nhưng mảng không Set, vậy làm sao cho nó Set mảng Nothing được? Nhưng Range thì lại được!

Trời... Mảng có phải là Object đâu là set với xiếc
Nói chung: Cứ thằng nào là biến ĐỐI TƯỢNG thì SET (Array là Variant, hổng phải Object)
 
Upvote 0
Cho nên Erase Array sau mỗi thủ tục có bị cho là thừa không?

Thích thì làm
Riêng tôi, nếu sau khi Erase xong, tôi nạp cái mới vào dùng tiếp thì tôi sẽ dùng Erase, còn không thì thôi, chả Erase gì gì cho mất công ---> Vì nếu quá máy móc, chả lẽ sau khi Dim n as Long... xài xong phải "ép" n = 0 trước End Sub chắc ---> Mệt!
 
Upvote 0
Thích thì làm
Riêng tôi, nếu sau khi Erase xong, tôi nạp cái mới vào dùng tiếp thì tôi sẽ dùng Erase, còn không thì thôi, chả Erase gì gì cho mất công ---> Vì nếu quá máy móc, chả lẽ sau khi Dim n as Long... xài xong phải "ép" n = 0 trước End Sub chắc ---> Mệt!

Em lại nghĩ rằng, nếu dùng tiếp mà không cần Erase cũng chẳng sao, trừ khi ta ReDim Preserve nó mới còn lưu lại giá trị, còn không thì nó cũng tự mất nội dung khi ta dùng vào việc mới.
 
Upvote 0
Thí nghiệm sẽ biết thôi

PHP:
Sub Test2()
  Dim Dic As Object
  Set Dic = CreateObject("Scripting.Dictionary")
  Dic.Add "a", 1
  Dic.Add "b", 2
  Dic.Add "c", 3
  Set Dic = Nothing
  MsgBox Dic Is Nothing
End Sub

Cho hỏi thêm, với dạng dưới đây thì làm sao set nó về Nothing được ạ?

PHP:
Sub Test1()
    With CreateObject("Scripting.Dictionary")
        .Add "a", 1
        .Add "b", 2
        .Add "c", 3
    End With
End Sub

Sau khi End With, tự nó có trả về nothing không?
 
Upvote 0
Cho hỏi thêm, với dạng dưới đây thì làm sao set nó về Nothing được ạ?

PHP:
Sub Test1()
    With CreateObject("Scripting.Dictionary")
        .Add "a", 1
        .Add "b", 2
        .Add "c", 3
    End With
End Sub

Sau khi End With, tự nó có trả về nothing không?

Theo mình đọc câu hướng dẫn thì tạm hiểu rằng sau khi End Sub Dic sẽ tự mất, cũng là ý kiến chủ quan thôi.
Xem ra vần đề này cũng không rõ ràng lắm hả. Đề tài cũng thú vị thật

When several object variables refer to the same object, memory and system resources associated with the object to which the variables refer are released only after all of them have been set to Nothing, either explicitly using Set, or implicitly after the last object variable set to Nothing goes out of scope.

Is there a definitive answer as to whether or not you should set all
objects to Nothing explicitly at the end of their scope, i.e. either when exiting
a function, terminating a class instance or shutting down a program?

The definitive answer, which I'm sure some will disagree with, is NO.
VB will automatically set all object variables to Nothing when they go out of
scope. For local variables, this happens when the procedure ends. For
module-level variables in class modules (including forms, controls, etc),
when the final release happens on the class (and after Class_Terminate is
run). For modules, when the program terminates. Setting them to Nothing
yourself is a waste of code: VB has to check if they are Nothing anyway and
always generates the code the code to release them, so you're just
duplicating existing code.
 
Lần chỉnh sửa cuối:
Upvote 0
Cho hỏi thêm, với dạng dưới đây thì làm sao set nó về Nothing được ạ?

PHP:
Sub Test1()
    With CreateObject("Scripting.Dictionary")
        .Add "a", 1
        .Add "b", 2
        .Add "c", 3
    End With
End Sub

Sau khi End With, tự nó có trả về nothing không?

Bạn cứ yên tâm dùng With... End With mà chẳng phải bận tâm gì về vụ Nothing nót thiết gì cả
Đi qua khỏi End With, Object sẽ "tự" biến mất
(chính vậy mà ít khi tôi dùng đến biến Object, trừ trường hợp buộc phải dùng ---> Còn lại thì cứ With.. End With mà phang)
 
Upvote 0
Hoàng trọng Nghĩa đã viết:
Với mảng thấy thường dùng Erase, thế nhưng mảng không Set, vậy làm sao cho nó Set mảng Nothing được? Nhưng Range thì lại được!

Trích Tổng quan về Scripting.Dictionary

- Phương thức RemoveAll: Phương thức RemoveAll sẽ xóa toán bộ những gì có trong Dictionary (nhưng không xóa chính nó).


When several object variables refer to the same object, memory and system resources associated with the object to which the variables refer are released only after all of them have been set to Nothing, either explicitly using Set, or implicitly after the last object variable set to Nothing goes out of scope.

Với tuyên bố này của bác Bill thì chẳng cần Set Nothing gì ráo. Mọi thứ sẽ tự động biến mất.
Kỹ năng tiếng anh của mình chưa đủ tốt nên có thể hiểu sai câu nói của bác Bill, nhưng tạm thời cứ thế này. Sau này giỏi thêm tí nữa sẽ điều chỉnh lại quan điểm.

Với kỹ năng tiếng Anh của mình cộng với cái logic cùn của mình thì chỉ từ 1 câu tiếng Anh đó không thể kết luận ngon lành như vậy.

Tạm dịch:

Khi nhiều biến đối tượng liên quan đến cùng 1 đối tượng, bộ nhớ và tài nguyên hệ thống liên kết đến đối tượng đó (dối tượng mà các biến liên kết đến), chỉ có thể giải phóng sau khi sử dụng phát biểu "Set" gán Nothing cho tất cả các biến; Dù biến có khai báo hay không, phải sau khi gán Nothing cho biến đối tượng cuối cùng.

Dĩ nhiên sau khi End Sub, các biến cục bộ sẽ được giải phóng, tôi không tranh cãi.
Tuy nhiên, tôi vẫn ủng hộ việc giải phóng bộ nhớ ngay khi không dùng đến nữa. Một thói quen tốt để "sau này ngu thêm tí nữa" vẫn quen tay làm việc tốt.
 
Lần chỉnh sửa cuối:
Upvote 0
Trích Tổng quan về Scripting.Dictionary

Với kỹ năng tiếng Anh của mình cộng với cái logic cùn của mình thì chỉ từ 1 câu tiếng Anh đó không thể kết luận ngon lành như vậy.

Tạm dịch:

Khi nhiều biến đối tượng liên quan đến cùng 1 đối tượng, bộ nhớ và tài nguyên hệ thống liên kết đến đối tượng đó (dối tượng mà các biến liên kết đến), chỉ có thể giải phóng sau khi sử dụng phát biểu "Set" gán Nothing cho tất cả các biến; Dù biến có khai báo hay không, phải sau khi gán Nothing cho biến đối tượng cuối cùng.

Dĩ nhiên sau khi End Sub, các biến cục bộ sẽ được giải phóng, tôi không tranh cãi.
Tuy nhiên, tôi vẫn ủng hộ việc giải phóng bộ nhớ ngay khi không dùng đến nữa. Một thói quen tốt để "sau này ngu thêm tí nữa" vẫn quen tay làm việc tốt.

Theo anh nói như thế thì mình đã biết chắc nó đã được giải phóng thì tại sao mình lại phải giải phóng nó nữa? Vậy có thể dư thao tác này không? Cái câu tiếng anh của bác Bill cũng khó hiểu quá nên em nhờ người dịch hộ thì ra thế này mà chắc gì đúng ý của bác Bill:

Khi có nhiều biến đối tượng tham chiếu đến cùng 1 đối tương, bộ nhớ và tài

nguyên hệ thống đươc sử dụng cho các biến đó sẽ chỉ được giải phóng sau

khi các biến được trả vể Nothing hoặc sau khi biến cuối cùng đi ra khỏi

phạm vi hoạt động dù có sử dụng câu Set rõ ràng hay không.
 
Lần chỉnh sửa cuối:
Upvote 0
Theo anh nói như thế thì mình đã biết chắc nó đã được giải phóng thì tại sao mình lại phải giải phóng nó nữa? Vậy có thể dư thao tác này không?

Vẫn xóa vì chưa biết nên tin ai. Theo bài của Hải (Microsoft) thì VBA tự xóa khi end sub, theo link của vodoi2x thì VBA xóa không triệt để.
 
Upvote 0
Mong anh Siwtom góp thêm ý kiến để mọi người có thêm kinh nghiệm, dù biết rằng thêm 1 câu lệnh nữa không nhiều nhưng không hiểu được bản chất vấn đề thì nghe sao sao ấy.
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom