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

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,077
Được thích
8,011
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
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.

Câu này hơi khó dịch, dịch sát nghĩa sẽ khó hiểu.

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, and after the last object variable set to Nothing goes out of scope.


memory and system resources associated with the object to which the variables refer are released
: Main clause

Main clause này có 2 sub clause nối bằng only:

- after all of them have been set to Nothing,
- after the last object variable set to Nothing
goes out of scope

When several object variables refer to the same object là 1 adverbial clause bổ nghĩa cho cả mệnh đề chính.
either explicitly using Set, or implicitly là adverb phrase bổ nghĩa cho sub clause thứ 1,

tôi dịch là Dù biến có khai báo hay không không đúng bằng QuangHai dịch là dù có dùng Set rõ ràng hay không, nhưng vẫn dễ hiểu.

Tới đoạn goes out of scope mà dịch là ra khỏi phạm vi hoạt động thì gượng quá.

Ghi chú:
Tây viết tiếng Tây không phải lúc nào cũng đúng văn phạm và rõ ràng dễ hiểu. Chẳng hạn dấu phẩy đỏ và chữ and đỏ tôi mới thêm vào, sẽ giúp rõ nghĩa hơn 1 tí tị.

Sau khi thêm như vậy có thể dịch lại:

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 đó, chỉ có thể giải phóng sau khi gán Nothing cho tất cả các biến, dù có dùng "Set" rõ ràng hay không; và sau khi biến đối tượng cuối cùng được gán Nothing hết hoạt động.

Thí dụ ta gán Dic1, Dic2, Dic3 cùng 1 đối tượng là Scripting.Dictionary, thì bộ nhớ chỉ giải phóng sau khi set cả 3 về Nothing. Dịch câu này chỉ để phản bác 1 điều rằng chỉ riêng câu này không thể kết luận "chẳng cần Set Nothing gì ráo. Mọi thứ sẽ tự động biến mất"

Câu kết luận này chỉ có thể đưa ra sau đoạn văn kế tiếp:
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 to release them, so you're just duplicating existing code.


Ngay cả đoạn này, chỉ cần xuống dòng và gạch đầu dòng đúng chỗ nó sẽ rõ ràng hơn biết bao nhiêu! Ku Tây viết đoạn này chỉ được 5 điểm môn văn.
 
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.

tiếng anh mình thì khá bị hạn chế nhưng xin đưa nội dùng này lên mong có bác đọc được và hiểu nó
NOTHING.jpg
Nothing 關鍵字是用來將一個物件變數從一個實際的物件裏分離開來
mình tạm dịch nó như sau : từ khóa này dùng để giải phóng đối tượng khỏi biến
(tức mình có thể dùng từ khóa trên để giải phóng biến tại bất khì thời điểm mình mong muôn)
或等待最後被設成 Nothing 的物件變數超出範圍之後。
hoặc nó sẽ tự giải phóng sau khi vượt khỏi phạm vi

tốm lại nó sẽ tự giải phóng khi kết thúc chương trình
 
Upvote 0
Hic, nhiều lúc chữ nào cũng biết nghĩa nhưng ráp vào 1 câu chả hiểu họ viết gì nữa, mặc dù tiếng anh của em cũng tạm được đó.
Em thấy bỏ bớt vài chữ coi bộ dễ hiễu hơn, nhưng bác Bill biết được cũng căng nghen

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, or after the last object variable set to Nothing goes out of scope.
 
Upvote 0
Hic, nhiều lúc chữ nào cũng biết nghĩa nhưng ráp vào 1 câu chả hiểu họ viết gì nữa, mặc dù tiếng anh của em cũng tạm được đó.
Em thấy bỏ bớt vài chữ coi bộ dễ hiễu hơn, nhưng bác Bill biết được cũng căng nghen

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, or after the last object variable set to Nothing goes out of scope.
nghe câu trên sợ quá dịch hết luôn
數個物件變數可以同時引用一個實際物件,nhiều biến có thể sự dụng cùng 1 đối tượng,
而當 Nothing 被指定給一個物件變數,nhưng nothing chỉ có thể thiết lập cho 1 đối tượng
那麼該變數將不再引用任何實際物件。khi biến không cần sử dụng bất kỳ đối tượng nào nữa
當數個物件變數同時引用一個物件,trong khi nhiều biến đang cùng sự dụng 1 đối tượng
那麼和該物件有關連的記憶體、nên các đối có sự liên quan về bộ nhớ
系統資源中被物件變數所引用到的部份,tài nguyên của hệ sẽ bị ảnh hưởng bởi các biến
只有在全部的物件變數都設成 Nothing 後才會被釋放。để giải phóng bộ nhớ khi tất cả các đối tượng được thiết lập thành nothing
而變數被設成 Nothing 的方法不外是直接使用 Set,việc thiết lập biến thành Nothing không ngoài việc sự dụng set
或等待最後被設成 Nothing 的物件變數超出範圍之後。hoặc đợi đến sau cùng Nothing được thiết lập khi biến nằm ngoài phạm vi

củ thể như trên đó, tại mình thấy những cái không cần thiết mình lọc bỏ đi thôi, không biết nội dung củ thể tiếng anh có phải vậy không ???

câu màu đỏ là câu kết luận đó.
 
Lần chỉnh sửa cuối:
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.

Tôi không đọc tài liệu về chuyện code trong VBA nhưng do tôi cũng từng viết trong Delphi nên tôi có thể kết luận ... khó biết lắm.
Tôi cho ví dụ trong Delphi. Ta xét Interface. Interface chỉ là interface, phải có một class nào đó implement cái interface kia. Về interface có cái gọi là "đếm số tham chiếu". Nó kiểu như có 1 cái phòng được dựng lên (1 đối tượng được tạo ra) và có 1 vị muốn làm việc với nó (tham chiếu). Mỗi khi có một vị nào đó "tham chiếu" tới cái phòng kia thì chỉ số của "đồng hồ đếm số tham chiếu" được tăng thêm 1, còn khi có vị nào đó "làm xong việc" và thôi không "quan tâm" nữa (interface = nil, nothing, set interface = nil, nothing) thì chỉ số của "đồng hồ đếm số tham chiếu" được giảm bớt 1. Khi chỉ số của "đồng hồ đếm số tham chiếu" = 0 (khi không còn vị nào "quan tâm" vì vị cuối cùng cũng "nhắn tin" là thôi không quan tâm - Set interface = Nothing) thì căn phòng - interface được "đập vỡ, tiêu hủy, hủy diệt" - căn phòng được phá đi. Vì có còn cần thiết nữa đâu?
Nếu nói về hàm để tăng chỉ số của "đồng hồ đếm số tham chiếu" thì đó là AddRef, còn lệnh giảm chỉ số của "đồng hồ đếm số tham chiếu" là Release.
Những người lập trình trong Delphi hầu như không phải gọi hàm AddRef và Release vì trong quá trình compile thì Delphi tự thêm vào những chỗ cần thiết các lệnh AddRef và Release.
Nhưng tôi thấy những người lập trình trong C++ bắt buộc phải tự mình gọi các hàm AddRef và Release.
Vậy thì tôi có câu hỏi: Như thế thì trong VBA thế nào? VBA có làm thay cho người lập trình như Delphi làm thay cho họ, hay VBA không làm thay giống như C++?
Tôi biết trong Delphi thế nào nhưng trong VBA thì chịu vì thứ nhất là tôi mới quan tâm tới VBA từ gần 1 năm nay, thứ nữa là khả năng tiếng Anh của tôi ở mức "luôn cầm từ điển trong tay và tra vài từ rồi đoán".
Dù thế nào chăng nữa thì viết Set dic = Nothing không ai dám nói là sai. Thậm chí viết:
Set dic = Nothing
Set dic = Nothing
Set dic = Nothing
cũng không ai dám nói là sai. Cùng lắm là nói: "thừa".
Nhưng các bạn cứ thử nghĩ xem. Một chuỗi "Set dic = Nothing" là mấy lần gõ? Mất mấy giây?. Và cái chuỗi đó ta viết trong code 10, 100, 1000 lần? Vậy thì viết chuỗi như thế mất thêm bao công sức, thời gian? Còn nếu nói về "thời gian thực hiện"? Ta giả sử là thực ra đối tượng sẽ được giải phóng khi ra khỏi Sub. Vậy thì viết thêm Set dic = Nothing thừa đến mức nào? Thực ra không là cái gì cả. VBA khi kiểm tra thấy dic = Nothing thì chả "giải phóng" cái gì cả. Thời gian, điện, nước chỉ tốn cho việc kiểm tra, nó chả là cái gì cả.
Vậy nếu là tôi, tức người không rõ cho lắm về những việc mà VBA làm sau "cánh gà", thì tôi sẽ viết Set dic = Nothing. Nó chả tốn mồ hôi, sức lực, điện nước là bao nhiêu nhưng tôi chắc 200% là tài nguyên được giải phóng, ngày ăn ngon miệng, tối ngủ yên giấc. Còn không thì vẫn nghi nghi hoặc hoặc, áy náy, không yên tâm. Trừ phi ông Microsoft xuất bản sách trong tiếng Việt của tôi và viết rõ ràng.
Tôi không phải là người quan tâm tiết kiệm từng xu nhưng lại vô tư phung phí hàng triệu. Có những code nếu viết cẩn thận một chút thì nó bù lại cho 1 tỷ tỷ thời gian mất vì set dic = Nothing. Kiểu tiết kiệm không phải chỗ.
Nếu cái Set dic = Nothing kia nó tốn quá nhiều công sức, thời gian điện nước thì tôi sẽ bỏ ra 1 ngày, 1 tháng, 1 năm để tìm hiểu rõ có cần hay không. Còn không thì quên đi cái chuyện tủn mủn như thế.
 
Upvote 0
Thức khuya vậy bác (hay cũng mất ngủ ... hihiiii)

Đúng là:
Tôi không phải là người quan tâm tiết kiệm từng xu nhưng lại vô tư phung phí hàng triệu. Có những code nếu viết cẩn thận một chút thì nó bù lại cho 1 tỷ tỷ thời gian mất vì set dic = Nothing. Kiểu tiết kiệm không phải chỗ.
Nếu cái Set dic = Nothing kia nó tốn quá nhiều công sức, thời gian điện nước thì tôi sẽ bỏ ra 1 ngày, 1 tháng, 1 năm để tìm hiểu rõ có cần hay không. Còn không thì quên đi cái chuyện tủn mủn như thế.

Viết thêm mấy chữ, nhưng áy náy không còn tập trung sức vào việc khác phải khỏe hơn không

Còn QuangHai muốn hiểu bản chất thì cứ đọc OPP đó, thì sẽ rõ tại sao lại sinh ra cái Set Obj nothing làm chi,

---------------
Trong VB hay VBA cũng như Delphi bác siwtom - nó sẽ tự gửi thông điệp đến sử dụng class chứa đối tượng đó để hủy đi, - song nếu ta thí nghiệm sẽ thấy nó sẽ làm việc này khi cùng trong code khi biên dịch luôn (tức là class đó ta viết cùng code sử dụng đối tượng luôn). TUY nhiên ở đây đối tượng Dictionary lại khác là nó lấy từ thành phần của Scripting (DLL) đã được biên dịch trước rồi - NÊN không rõ nó có biên dịch việc (set nothing) đó cho đối tượng sử dụng ngoài vậy không - NÊN đặt Set Nothing là không thừa
 
Upvote 0
Thức khuya vậy bác (hay cũng mất ngủ ... hihiiii)

Đúng là:


Viết thêm mấy chữ, nhưng áy náy không còn tập trung sức vào việc khác phải khỏe hơn không

Còn QuangHai muốn hiểu bản chất thì cứ đọc OPP đó, thì sẽ rõ tại sao lại sinh ra cái Set Obj nothing làm chi,

---------------
Trong VB hay VBA cũng như Delphi bác siwtom - nó sẽ tự gửi thông điệp đến sử dụng class chứa đối tượng đó để hủy đi, - song nếu ta thí nghiệm sẽ thấy nó sẽ làm việc này khi cùng trong code khi biên dịch luôn (tức là class đó ta viết cùng code sử dụng đối tượng luôn). TUY nhiên ở đây đối tượng Dictionary lại khác là nó lấy từ thành phần của Scripting (DLL) đã được biên dịch trước rồi - NÊN không rõ nó có biên dịch việc (set nothing) đó cho đối tượng sử dụng ngoài vậy không - NÊN đặt Set Nothing là không thừa

Tất nhiên server đã tồn tại từ lâu và các object mà server có thể tạo thì đã được đăng ký trong system rồi.
Ví dụ ta viết code:

Set dic = CreateObject("Scripting.Dictionary")
With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")

thì từ đâu biết được là đối tượng nào được tạo và do "ai" tạo?
Thì mọi thứ đã được ghi từ lâu trong Registry rồi.
Nếu bạn mở Registry: run --> regedit --> Edit --> Find --> Scripting.Dictionary hoặc {1C3B4210-F441-11CE-B9EA-00AA006B1A69}
thì bạn sẽ thấy hình như dưới đây

View attachment 92953



View attachment 92954




Các {EE09B103-97E0-11CF-978F-00A02463E06F} hay
{1C3B4210-F441-11CE-B9EA-00AA006B1A69}
là những CLSID - Class ID
Nhánh HKEY_CLASSES_ROOT\CLSID\
nhiều CLSID vô kể.
Nếu bạn mở khóa {EE09B103-97E0-11CF-978F-00A02463E06F} - Scripting.Dictionary
thì bạn nhìn thấy hình như dưới đây


View attachment 92955

Tức object do scrrun.dll tạo.
{1C3B4210-F441-11CE-B9EA-00AA006B1A69} thì là DataObject.
Tóm lại mọi object - interface có thể có trong system thì thông tin đã được ghi trong registry.
------------
Khi bạn viết CreateObject thì ông chủ system biết "bắt" ai phải tạo object và tạo object gì.
"Khách hàng", tức là bạn hay code của bạn, có được object - interface đó là do có POINTER tới interface đó.
Với interface thì có cái gọi là "đếm số tham chiếu" - AddRef (tăng thêm 1) và Release (giảm đi 1). Khi số tham chiếu = 0 thì system "hủy diệt" interface. Không có thông điệp (message) gì ở đây.
Ta có thể giảm số tham chiếu bằng cách viết Set dic = Nothing. Nhưng nếu đúng là VBA làm hộ ta thì có nghĩa là VBA đã làm hộ ta khi ra khỏi SUB bằng cách "thêm" vào một "đoạn" code.
Vấn đề chưa rõ lắm chỉ là: liệu VBA có tự thêm vào code giảm số tham chiếu hay không (khi ra khỏi SUB)? Nếu có thì ta khỏi viết Set dic = Nothing, thế thôi.
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Giả xử tôi có Class1 (minh hoạ cho các object/class cụ thể khác).
Trong VBA khi tạo một object trong một SUB/FUNCTION:

Dim obj as Class1
Set obj = CreateObject("...Class1") hoặc Set obj = New Class1 hoặc Dim obj As New Class1, VBA khởi tạo một vùng nhớ để cho nó hoạt động.

Nếu tôi viết 2 dòng lệnh
(1) Set obj = New Class1
(2) Set obj = New Class1
Trong bộ nhớ lúc này đang tồn tại hai vùng nhớ cho 2 đối tượng kiểu Class1 đang hoạt động, nhưng biến obj lưu địa chỉ của vùng nhớ tạo lần cuối cùng. Có nghĩa nếu bạn muốn điều khiển obj khởi tạo ở (1) thì rất khó vì mất địa chỉ, chỉ biết nó đang lưu lạc đâu đó.

Cuối SUB/FUNCTION tôi không dùng nữa thì Set obj = Nothing -> vùng nhớ (2) được giải phóng ngay, khi thoát khỏi SUB/FUNCTION VBA cũng tự động Set tất cả các biến object về Nothing, lúc này vùng nhớ (1) cũng được giải phóng. Vậy khi không còn dùng nữa thì Set object = Nothing nếu không làm thì VBA cũng Set object = Nothing nếu các biến obj đó không còn khả năng lưu hành trong phạm vi code của bạn.

Như vậy, nếu cuối SUB/FUNCTION không dùng tới Set obj = Nothing thì VBA tự làm cho chúng ta. Tuy nhiên trong tiến trình của SUB/FUNCTION không dùng nữa chúng ta cần thiết gán Set obj = Nothing để giải phóng nó (phá huỷ nó). Bạn hình dung, bạn đang có 2 cửa hàng phải thuê, nếu 1 cửa hàng không còn dùng đến nó thì cần hủy nó ngay chứ để đến cuối năm (cuối SUB/FUNCTION, set obj = Nothing bởi bạn hay VBA) mới hủy nó thì mất toi tiền nuôi nó (bộ nhớ bị chiến dụng), để nó tồn tại ở hoàn cảnh nào đó (sự độc lập) có thể không hại chủ, tuy nhiên nếu cửa hàng đó vẫn tồn tại và liên lụy tới ông chủ thì có đáng tiêu diệt nó không. Ví dụ Class1 có viết sự kiện cho việc nhấp đúp chuột vào bảng tính. Nếu tạo nó 2 lần thì sự kiện nhấp đúp chuột chạy 2 lần, trong khi chỉ cần 1 lần.

Phần lớn các Class/Object được thiết kế chuẩn khi biến kiểu của nó gán là Nothing thì người lập trình viết tất cả các lệnh cần thiết để giải phóng bộ nhớ (trong VB/VBA chính là sự kiện Class_Terminate(), trong Delphi là Destroy()). Tuy nhiên vì lý do đặc thù nào đó mà một phần của nó không được giải phóng hết thì ta cần đọc tài liệu để biết cần chạy SUB/FUNCTION nào trước khi gán nó là Nothing. Ví dụ các đối tượng trong VBA: Excel.Application, Word.Application,..., thủ tục Quit() là cần phải chạy, với ADO là ADODB.Connection thủ tục Close() cần phải chạy.
Nếu code của bạn là

Dim MyApp As Object
Set MyApp = CreateObject("Excel.Application")
MyApp.Visible = True

Cuối SUB/FUNCTION dù bạn gán MyApp = Nothing hay không thì Excel vẫn đang tồn tại trong bộ nhớ.

Về thủ tục Quit, Close chỉ biết khi đọc tài liệu gốc, những lưu ý từ nhà lập trình ra nó, hoặc kinh nghiệm sử dụng lâu mới biết được.

Với tôi thì luôn làm theo một tôn chỉ, những đối tượng tạo bởi CreateObject(), Set...New nếu không dùng đến luôn giải phóng nó Set...Nothing, dù biết có những việc VBA tự làm cho mình.
 
Upvote 0
Theo quan điểm của mình thì nếu là 1 lập trình viên chuyên nghiệp thì mỗi một câu lệnh đều phải mang ý nghĩa riêng của nó.
Còn đối với những người tham gia cho vui, hoặc chỉ để xử lý công việc thì cứ thêm cái dòng code vô hại đó vào trước khi End Sub chắc cũng không ảnh hưởng gì.
 
Upvote 0
Theo quan điểm của mình thì nếu là 1 lập trình viên chuyên nghiệp thì mỗi một câu lệnh đều phải mang ý nghĩa riêng của nó.
Còn đối với những người tham gia cho vui, hoặc chỉ để xử lý công việc thì cứ thêm cái dòng code vô hại đó vào trước khi End Sub chắc cũng không ảnh hưởng gì.

Lấy 1 ví dụ khác nhé:
- Khi viết code, đôi khi phải dùng qua 1 biến tạm để nhằm tăng tốc chạy code ---> Tôi thí nghiệm và chắc chắn việc làm này là hiểu quả, vậy tôi sẽ làm (tăng hiệu suất làm việc)
- Khi đặt tên biến, tôi học được cách đặt tên sao cho cô động súc tích, để bất kỳ ai (dù là Tây hay Ta) nhìn vào cũng biết được tác dụng của biến thông qua cái tên (bố trí code cho dễ đọc)
vân... vân...
--------------
Vậy Set Nothing gì gì đó, làm cũng tốt mà không làm cũng không sao ---> Ít nhất với trình độ của tôi hiện giờ, tôi chả thấy có Nothing vào nó "ngon" hơn gì so với không có Nothing cả
Với tôi, người học lập trình không qua trường lớp thì KINH NGHIỆM là thứ quan trọng nhất ---> Cứ thí nghiệm rồi tự rút ra kết luận ---> Vậy chắc chắn rằng đến khi nào tôi thấy nó CẦN THIẾT thì tôi sẽ dùng... Hoặc đến khi nào tôi đủ sức viết 1 chương trình lớn và thấy rằng nếu không có Set Nothing thì máy tính sẽ "nặng" và "treo" chẳng han, thì tôi sẽ dùng
Đơn giản vậy thôi!
Ẹc... Ẹc...
 
Upvote 0
Có mấy ý góp chuyện thế này với anh nhé!

Trở về gần ...20 năm trước lúc VBA mới khai sinh. Thời điểm đó 1 chiếc PC chỉ có khoảng vài trăm KB bộ nhớ, khủng lắm là vài MB.
http://en.wikipedia.org/wiki/Visual_Basic_for_Applications

Do hạn hẹp về bộ nhỚ nên các bậc sinh thành ra VBA mới nghĩ đến việc phải giải phóng bộ nhớ cho các ObjecT khi xong việc. Bởi một Object bình thường khi được sử dụng đến sẽ chiếm khoảng vài Byte đến vài KB nghĩa là ở thời điểm đó sẽ chiếm dụng tương đối dung lượng RAM (vài %).

Trở lại hiện thực 20 năm sau, năm 2012 mỗi chiếc PC hiện nay đã trang bị từ 2GB đến 32GB. Kể cả 1 chiếc máy PC đời cũ cũng có khoảng 256MB (Đời máy 2004) nghĩa là về dung lượng RAM đã gấp khoảng mấy trăm.. hoặc đúng hơn là vài ngàn lần so với thời điểm khi mà VBA mới ra đời. Chưa kể các hệ điều hành hiện nay đều có cơ chế quản lý bộ nhớ tối ưu hơn rất nhiều so với bản Windows 9x trước đó. Do vậy kể cả một chương trình có ngốn hết gần hết số RAM của bạn nhưng chẳng may bị đơ (crash) - mất khả năng quản lý bộ nhớ đã chiếm dụng thì sau khi nó bị Windows kick out xong, những gì mà nó lưu giữ trong RAM cũng được Windows giải thoát trong vòng vài giây.

Trừ khi là bạn phải dùng Object vài trăm lượt hoặc nhiều hơn, nếu chỉ dùng đến Object vài lượt thì cũng không cần quá bận tâm làm gì. Windows hoặc Compiler hiện nay đã rất thông minh và nhiệt tình để giải quyết gần hết những việc vụn vặt này.

Tuy nhiên, nếu có "mở bải - thân bài - kết luận" cho mỗi Object thì nhìn có vẻ hay hơn nhỉ?
 
Lần chỉnh sửa cuối:
Upvote 0
Có mấy ý góp chuyện thế này với anh nhé!

Trở về gần ...20 năm về trước lúc VBA mới khai sinh. Thời điểm đó 1 chiếc PC chỉ có khoảng vài trăm KB bộ nhỡ, khủng lắm là vài MB.
http://en.wikipedia.org/wiki/Visual_Basic_for_Applications

Do hạn hẹp về bộ nhỚ nên các bậc sinh thành ra VBA mới nghĩ đến việc phải giải phóng bộ nhớ cho các ObjecT. Bởi một Object bình thường khi được sử dụng đến sẽ chiếm khoảng vài Byte đến vài KB nghĩa là ở thời điểm đó sẽ chiếm dụng tương đối dung lượng RAM (vài %).

Trở lại hiện thực 20 năm sau, năm 2012 mỗi chiếc PC hiện nay đã trang bị từ 2GB đến 32GB. Kể cả 1 chiếc máy PC đời cũ cũng có khoảng 256MB (Đời máy 2004) nghĩa là về dung lượng RAM đã gấp khoảng mấy trăm.. hoặc đúng hơn là vài ngàn lần so với thời điểm khi mà VBA mới ra đời. Chưa kể các hệ điều hành hiện nay để có cơ chế quản lý bộ nhớ tối ưu hơn rất nhiều so với bản Windows 9x trước đó. Do vậy kể cả một chương trình có ngốn hết gần hết số RAM của bạn nhưng chẳng may bị đơ (crash) thì sau khi nó bị Windows kick out xong thì những gì mà chiếm trong bộ nhớ RAM cũng được Windows giải thoát trong vòng vài giây.

Trừ khi là bạn phải dùng Object vài trăm lượt hoặc nhiều hơn, nếu chỉ dùng đến Object vài lượt thì cũng không cần quá bận tâm làm gì. Windows hoặc Compiler hiện nay đã rất thông minh và nhiệt tình để giải quyết gần hết những việc vụn vặt này.

Tuy nhiên, nếu có "mở bải - thân bài - kết luận" cho mỗi Object thì nhìn có vẻ hay hơn nhỉ?
Nghe có vẻ giống như việc người ta tranh luận nhau có nên dọn sạch file tmp trên máy tinh hay không ấy nhỉ?
Ẹc... Ẹc... nghe cũng có lý!
 
Upvote 0
Dọn dẹp sạch sẽ sau khi dùng xong là một thói quen tốt.

Các bạn tìm hiểu về Stack và Heap là rõ thôi.
Link: http://dotnet.edu.vn/ChuyenMuc/Tim-hieu-Stack--Heap-trong-C-411.aspx

P/S: với các biến dùng trong các sub/function (thực hiện trong stack) sẽ tự động bị dẹp khi dùng xong, nên tui cũng hay lười không Set nothing. nhưng mà nếu dùng nhiều object trong đó thì cũng nên set nothing khi dùng xong mỗi cái cho đỡ vướng.
 
Upvote 0

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

Back
Top Bottom