Object.close và Set Object = nothing

Liên hệ QC
Tôi tuân thủ nội quy khi đăng bài

syquyen1987

Thành viên hoạt động
Tham gia
8/7/18
Bài viết
193
Được thích
43
Các Anh có thể cho hỏi nếu "đối tượng" mà được mở và có câu lệnh Set Object = ..... Thì sau khi hoàn thành mà quên không Object.close và Set Object = nothing thì có nghe nói là sẽ chiếm bộ nhớ càng nhiều khi mỗi lần chạy code. Nhờ các anh có thể giải thích giúp bản chất là như thế nào không ạ. Xin cảm ơn ạ
 
Nếu chỉ có 1 sub/ function thì không sao cả.
Mỗi lần run thì nó set object lại, nên 1 thời điểm chỉ có 1 object tồn tại.
Chỉ khi nào có nhiều sub/function lồng ghép trong 1 big project, khi chạy các sub A thì các objects của sub B,C,D trước đó đã mở, không cần sử dụng nữa mà không xóa nó đi thì tốn tài nguyên và làm chậm máy
 
Upvote 0
Mới tuyển được cô trợ lý này:

View attachment 292665

Khi mọi người tin cậy vào ChatGPT, động một cái là nhờ nó trả lời rồi cũng hiểu theo nó một cách chung chung thậm chí có thể sai thì thật là tệ hại. Câu trả lời không đúng với câu hỏi, hoặc trả lời đại khái, chung chung có thể do cách hỏi, cách gài từ khóa trong câu hỏi không chuẩn, hoặc ChatGPT copy nguồn trên internet không chuẩn.
 
Upvote 0
@syquyen1987
Lệnh Set là gán biến đối tượng với một đối tượng lớp hoặc thư viện được khởi tạo với vị trí bộ nhớ mới để truy cập, hoặc gán biến với vị trí con trỏ của lớp hoặc thư viện đã khởi tạo có sẵn trong bộ nhớ chờ gọi. Lớp hoặc thư viện có thể chiếm dụng dung lượng lưu trữ lớn nên việc giải phóng là cần thiết. Nhưng tùy chương trình đang viết.

Biến đối tượng nó cũng có vị trí bộ nhớ riêng để truy cập, khi giải phóng chỉ lớp hoặc thư viện được giải phóng khỏi bộ nhớ. Biến được giải phóng khi kết thúc hàm, thủ tục, lớp, thư viện, ứng dụng.

Đầu tiên phải học hiểu khởi tạo Lớp và thư viện. Quá trình tải thư viện để chạy chương trình là tốn kém, tùy trường hợp mà xử lý trong mã phù hợp với chương trình. Trong đó có hai cách khai báo:
  1. Khai báo sớm - Earley Binding: lớp, thư viện được khởi tạo hoặc tải trước khi mã truy cập. Mã chạy nhanh ngay lần đầu, nhưng gây hao bộ nhớ cả quá trình ứng dụng hoạt động. Khai báo sớm chỉ sử dụng khi viết mã, khi mã tận dụng tối đa các phương thức, hàm đối tượng, lớp trong thư viện.
  2. Khai báo muộn - Late Binding: lớp, thư viện được khởi tạo hoặc tải khi mã chuẩn bị truy cập. Mã sẽ chậm khi chạy lần đầu. Gây tốn kém CPU, nếu khởi tạo và giải phóng không hợp lý. Khai báo muộn sử dụng khi quá trình gọi với tần suất thấp.

Vì quá trình khởi tạo và giải phóng có thể gây tốn kém CPU, nên việc lựa chọn giữa CPU và RAM rất cần thiết. Nếu lớp hoặc thư viện được gọi liên tục thì chỉ giải phóng khi kết thúc chương trình.

Với VBA: Lệnh Set giải phóng khi Biến đối tượng thuộc biến toàn cục và ít được truy cập.

Ví dụ: Set obj = New Excel.Application lệnh này tạo cả một ứng dụng Excel hoạt động trong tiến trình riêng, đồng thời có vị trí bộ nhớ riêng, với bộ nhớ truy cập gán vào biến obj. Với Application có thể sẽ mở Workbook và các cửa sổ. Trong đó có các lệnh Quit, Close để đóng từng Workbook, và các cửa sổ để giải phóng bộ nhớ. Nếu không đóng với lệnh quit, close, thì bộ nhớ phải hoạt động cho đến khi biến obj được giải phóng. Trong khi đó thư viện ứng dụng Excel.Application là rất lớn.


Để tiết kiệm bộ nhớ và CPU không chỉ phụ thuộc lệnh set, còn phụ thuộc vào nhiều yếu tố khác: quá trình viết mã, tham chiếu thư viện, tham chiếu API, mã trong classes hay trong module, ...
 
Upvote 0
Các Anh có thể cho hỏi nếu "đối tượng" mà được mở và có câu lệnh Set Object = ..... Thì sau khi hoàn thành mà quên không Object.close và Set Object = nothing thì có nghe nói là sẽ chiếm bộ nhớ càng nhiều khi mỗi lần chạy code. Nhờ các anh có thể giải thích giúp bản chất là như thế nào không ạ. Xin cảm ơn ạ
Đơn giản thì cái mà bạn "nghe nói" ấy SAI, hoặc bạn nghe không hiểu cho nên lặp lại SAI NGỮ CẢNH.

Lời giải thích (cóp trên mạng) ở bài #4 vì dựa trên thực hành (AI) cho nên thiếu hẳn đi phần lý thuyết.

Các lời giải thích chỉ quy vào bộ nhớ thì là hạn hẹp. Đối tượng không chỉ chiếm bộ nhớ, nhiều đối tượng chiếm hữu các tài nguyên khác. Ví dụ cổng kết nối với Server là một tài nguyên; một Server chỉ cung cấp n cổng, nếu object của bạn chiếm 1 thì Server chỉ còn n-1; vì vậy khi dùng xong, bạn nên bảo object ấy giải phóng nó.

Giải phóng bằng cách nào?
Có hai cách:
1. Đối tượng cung cấp một phương thức gì đó. Gọi phương thức này thì đối tượng sẽ giải phóng các tài nguyên mà nó đang chiếm hữu. Điển hình đối tượng căn bản trong Java có phương thức Close().
2. Nếu chương trình chạy trên nền tảng gì đó có bộ phận dọn rác (garbage collector) thì khi đối tượng bị hủy, bộ phận dọn rác sẽ đi thanh toán các tài nguyên mà đối tượng đang chiếm giữ.
Lưu ý là từ "giải phóng" chỉ áp dụng cho liên hệ giữa tài nguyên và đối tượng trước mắt. Khi đối tượng giải phóng tài nguyên không có nghĩa là tài nguyên sẽ "free". Nếu nhiều đối tượng "share" tài nguyên ấy thì khi nào tất cả đều giải phóng, tài nguyên mới hoàn toàn "free".

Trường hợp của VBA (VBA là nền tảng chạy code có bộ phận dọn rác):
Tài nguyên có ba loại, loại software (thường chỉ chiếm hữu bộ nhớ), loai hardware (tỷ dụ như máy in, băng thông,...), và loại linh tinh (như cổng nối với Server).
Trong VBA đối tượng được giữ bằng biến. Một đối tượng có thể có nhiều biến trỏ vào.
Lệnh Set BiếnA = Đối_Tượng_X trỏ BiếnA vào Đối_Tượng_X
Lệnh Set BiếnA = Nothing bứt biến BiếnA ra khỏi Đối_Tượng_X
Bộ máy dọn rác sẽ xét Đối_Tượng_X.
- Nếu còn biến khác trỏ vào nó thì để yên
- Nếu không còn biến nào trỏ vào thì:
- - Nếu là đối tượng cố hữu của nền tảng VBA (hay Access/Excel,...) như WporkSheet, Range thì để yên.
- - Nếu là đối tượng của hệ thống hay nên tảng khác (như ADODB, RegExp, Dictionary,...) thì tháo kết nối và phải phóng các tài nguyên mà đối tượng đang chiếm giữ (thường chỉ là bộ nhớ hoặc cổng kết nối)
- - Nếu là đối tượng riêng của chương trình dựng ra thì giải phóng các tài nguyên mà đối tượng đang chiếm giữ.

Vì vậy, trên nguyên tắc, nếu bạn viết một code dài và phức tạp thì khi dùng xong nên set đối tượng thành nothing để giải phóng tài nguyên.

Tuy nhiên, nếu code chỉ đơn giản (hầu hết các code trên GPE khá đơn giản, ít gọi đi gọi lại các Sub/Function, ít xảy ra đệ quy, và nhất là ít khi giành dựt hardware) cho nên có thể làm ngơ vì hai trường hợp sau:

1. Các đối tượng được dựng lên nhưng không gán tên biến - trườnghợp điển hình là dùng lệnh With CreateObject(...). Trường hợp này, With-End With xác định tầm vực của dối tượng được dựng ra. Khi chạy hết tầm vực này, VBA tự động để cho cỗ máy dọn rác hủy đối tượng và giải phóng tài nguyên.

2. Biến trỏ vào đối tượng đi hết giới hạn tầm vực của nó. Biến nội có tầm vực là Sub/Function chứa chúng. Khi Sub/Function chạy xong (Exit hay End) thì các biến nội hết tầm vực và sẽ bị VBA hủy; kế đó cỗ máy dọn rác sẽ tự biết thanh toán các đối tượng. Biến toàn cục (và biến Static) có tầm vực là cả chương trình (prioject) cho nên chương trình phải chạy xong chúng mới hết tầm vực. Nên lưu ý là điểm này rất quan trọng trong câu chuyện Set Object = Nothing (xem bên dưới).

Túm lại:

(i) Bình thường, với trình độ viết code của GPE thì nếu Object là biến nội, việc Set = Nothing không quan trọng lắm. Cứ để mặc cho đến lúc chúng chạy hết tầm vực sẽ tự giải phóng tài nguyên - trừ phi tài nguyên là hardware hay cổng kết nối.

(ii) Nếu là biến toàn cục thì LUÔN LUÔN set = Nothing sau khi dùng xong.

(iii) Nếu là biến Static thì phải theo dõi cho sát, jhi nào có thể set = Nothing thì làm.

(iv) Các Objects được dựng ra mà không gán tên (như lệnh With) thì để cho VBA lo. Vả lại không có tên biến thì lấy gì set = nothing?

Chú thích:
Nối về tài nguyên bộ nhớ thì các kiểu phức tạp như String, Array cũng có thể chiếm dụng rất nhiều bộ nhớ. Và chúng cũng cần giải phóng. Nhưng đó là đề tài khác. Tôi khong nói thêm ở đây
 
Lần chỉnh sửa cuối:
Upvote 0
1/ tốt nhất nên set xx = Nothing không có gì dài dòng và phức tạp cả chỉ có 1 dòng code có 3 từ + cái dấu = mà thôi

2/ còn With thì không có gì mà set cả như bài trên đã nêu

3/ trình code hạng xx thì nên khai báo mọi cái trong phạm vi của Function + Sub còn biết kiểm soát nó đi đâu về đâu

sau này code khá hơn thì muốn khai báo ngoài hàm sử dụng chung cũng được nhưng phải biết kiểm soát nó đi đâu về đâu

4/ VBA lỗi thời nhất khai báo tào lao các kiểu cũng xong ( Bỏ Option Explicit đi ) ...

mới tập tành code nên khai báo tường minh và biết kiểm soát sử dụng các biến thì sau này qua ngôn ngữ khác viết nó sẽ tốt hơn mà ít dính báo Virus giả như cách ai đó khai báo tào lao trên VBA

5/ khoãng 10 năm trước trên này ồn ào chuyện set Dic = Nothing ... keo là không cần thiết vì quá nhỏ .. trả qua viết vài hàm xx trên VBA nên không cần

khi viết các hàm bao quát lớn hơn trên các ngôn ngữ khác khởi tạo các Object lồng nhau xem sẽ thấy thôi
 
Lần chỉnh sửa cuối:
Upvote 0
Các Anh có thể cho hỏi nếu "đối tượng" mà được mở và có câu lệnh Set Object = ..... Thì sau khi hoàn thành mà quên không Object.close và Set Object = nothing thì có nghe nói là sẽ chiếm bộ nhớ càng nhiều khi mỗi lần chạy code. Nhờ các anh có thể giải thích giúp bản chất là như thế nào không ạ. Xin cảm ơn ạ
Mình là dân không chuyên, cũng đã từng thắc mắc vụ này cách đây khoảng chục năm. Đã nhận được nhiều câu trả lời là nên và phải set xxx = Nothing nếu không máy tính sẽ đầy rác và dẫn đến bộ nhớ sẽ này sẽ nọ.

Nhưng dựa theo kinh nghiệm thực tế, mình đã và đang viết code VBA cho khoảng 50 máy tính chạy chương trình quản lý sản xuất. Mình có thói quen xấu là chưa bao giờ Set xxx = Nothing. Tuy nhiên, mình chưa lần nào bị rắc rối liên quan đến vụ này.

Cho nên mình ủng hộ việc cứ để cho máy tính tự lo liệu việc dọn rác do VBA tạo ra.

Tuy nhiên, giết lầm hơn bỏ sót. Cứ việc Set xxx= Nothing cũng không mất nhiều thời gian.
 
Upvote 0
Mình là dân không chuyên, cũng đã từng thắc mắc vụ này cách đây khoảng chục năm. Đã nhận được nhiều câu trả lời là nên và phải set xxx = Nothing nếu không máy tính sẽ đầy rác và dẫn đến bộ nhớ sẽ này sẽ nọ.
Đúng, chuyện này 10 năm trước ở đây đã có bàn qua rồi.

Nhưng dựa theo kinh nghiệm thực tế, mình đã và đang viết code VBA cho khoảng 50 máy tính chạy chương trình quản lý sản xuất. Mình có thói quen xấu là chưa bao giờ Set xxx = Nothing. Tuy nhiên, mình chưa lần nào bị rắc rối liên quan đến vụ này.
Như đã nêu ở bài trước, code của bạn không có nhiều sub/function, không có đệ quy thì rất hiếm khi xảy bị kẹt tài nguyên.

Một số phần mềm Windows về sau này được cải tiến để tách rời code ra khỏi dữ liệu. Nhờ vậy chúng có khả năng code chỉ load một lần cho nhiều đối tượng khác nhau.

Khoảng chục năm trước, ADODB vẫn còn vấn đề bị bể bộ nhớ. Cho nên ở hệ thống cũ, đối tượng loại này nên được giải phóng sau khi dùng để tránh Excel crash. Vả lại, ADO cũng có thể khóa đường nối với CSDL cho nên việc giải phóng là rất nên.

Cho nên mình ủng hộ việc cứ để cho máy tính tự lo liệu việc dọn rác do VBA tạo ra.

Tuy nhiên, giết lầm hơn bỏ sót. Cứ việc Set xxx= Nothing cũng không mất nhiều thời gian.
Giết lầm hơn bỏ sót là chính sách của Tào Tháo, làm chính trị thì được nhưng không thể áp dụng cho lập trình.
Đối với lập trình, lầm và sót đều là sai.

Phương án "cứ để cho máy tính tự lo liệu" đại trà như vậy là sai.
Như tôi đã trình bày rõ rệt ở bài trước, có lẽ bạn may mắn là các objects của bạn đều được dựng theo biến nội. Gặp một mớ biến toàn cục mà không giải phóng chạy một hồi nó ì ạch luôn.
Rất may cho bạn là biến toàn cục dùng bộ nhớ ụ (heap memory), lớn rất nhiều so với biến nội dùng bộ nhớ ngăn xếp (stack). Tuy nhiên, tài nguyên không chỉ riêng là bộ nhớ. Tài nguyên có loại riêng (của riêng chương trình, máy của bạn); nhưng cũng có loại chung như cổng kết nối, máy in,...
 
Upvote 0
Tôi nhớ mang máng mơ màng đâu đó trên Google đại ý nó nói trong cái ADO.NET mới viết sau này có khả năng tự dọn dẹp rác khi khởi tạo Object

còn cái ADODB của 20 na9m trước thì khác ... phỏng biết google nó phán trúng hay sai

còn tôi thì không biết nó nói đúng hay sai ????
 
Upvote 0
@syquyen1987
Lệnh Set là gán biến đối tượng với một đối tượng lớp hoặc thư viện được khởi tạo với vị trí bộ nhớ mới để truy cập, hoặc gán biến với vị trí con trỏ của lớp hoặc thư viện đã khởi tạo có sẵn trong bộ nhớ chờ gọi. Lớp hoặc thư viện có thể chiếm dụng dung lượng lưu trữ lớn nên việc giải phóng là cần thiết. Nhưng tùy chương trình đang viết.

Biến đối tượng nó cũng có vị trí bộ nhớ riêng để truy cập, khi giải phóng chỉ lớp hoặc thư viện được giải phóng khỏi bộ nhớ. Biến được giải phóng khi kết thúc hàm, thủ tục, lớp, thư viện, ứng dụng.

Đầu tiên phải học hiểu khởi tạo Lớp và thư viện. Quá trình tải thư viện để chạy chương trình là tốn kém, tùy trường hợp mà xử lý trong mã phù hợp với chương trình. Trong đó có hai cách khai báo:
  1. Khai báo sớm - Earley Binding: lớp, thư viện được khởi tạo hoặc tải trước khi mã truy cập. Mã chạy nhanh ngay lần đầu, nhưng gây hao bộ nhớ cả quá trình ứng dụng hoạt động. Khai báo sớm chỉ sử dụng khi viết mã, khi mã tận dụng tối đa các phương thức, hàm đối tượng, lớp trong thư viện.
  2. Khai báo muộn - Late Binding: lớp, thư viện được khởi tạo hoặc tải khi mã chuẩn bị truy cập. Mã sẽ chậm khi chạy lần đầu. Gây tốn kém CPU, nếu khởi tạo và giải phóng không hợp lý. Khai báo muộn sử dụng khi quá trình gọi với tần suất thấp.

Vì quá trình khởi tạo và giải phóng có thể gây tốn kém CPU, nên việc lựa chọn giữa CPU và RAM rất cần thiết. Nếu lớp hoặc thư viện được gọi liên tục thì chỉ giải phóng khi kết thúc chương trình.

Với VBA: Lệnh Set giải phóng khi Biến đối tượng thuộc biến toàn cục và ít được truy cập.

Ví dụ: Set obj = New Excel.Application lệnh này tạo cả một ứng dụng Excel hoạt động trong tiến trình riêng, đồng thời có vị trí bộ nhớ riêng, với bộ nhớ truy cập gán vào biến obj. Với Application có thể sẽ mở Workbook và các cửa sổ. Trong đó có các lệnh Quit, Close để đóng từng Workbook, và các cửa sổ để giải phóng bộ nhớ. Nếu không đóng với lệnh quit, close, thì bộ nhớ phải hoạt động cho đến khi biến obj được giải phóng. Trong khi đó thư viện ứng dụng Excel.Application là rất lớn.


Để tiết kiệm bộ nhớ và CPU không chỉ phụ thuộc lệnh set, còn phụ thuộc vào nhiều yếu tố khác: quá trình viết mã, tham chiếu thư viện, tham chiếu API, mã trong classes hay trong module, ...
Em đọc thì không hiểu hết được những gì anh nói. Nhưng có một vấn đề em muốn đề cập rằng: Em luôn luôn chọn khai báo muộn để những máy tính khác sử dụng thì coding chạy được. Còn nếu mà khai báo sớm thì máy tính đó phải tích vào thư viện tương ứng thì mới chạy được coding ạ
Bài đã được tự động gộp:

Đúng, chuyện này 10 năm trước ở đây đã có bàn qua rồi.


Như đã nêu ở bài trước, code của bạn không có nhiều sub/function, không có đệ quy thì rất hiếm khi xảy bị kẹt tài nguyên.
Trong trường hợp mà bị kẹt tài nguyên thì như thế nào ạ, anh có thể nói cho em được mở mang kiến thức được không ạ?

Một số phần mềm Windows về sau này được cải tiến để tách rời code ra khỏi dữ liệu. Nhờ vậy chúng có khả năng code chỉ load một lần cho nhiều đối tượng khác nhau.

Khoảng chục năm trước, ADODB vẫn còn vấn đề bị bể bộ nhớ. Cho nên ở hệ thống cũ, đối tượng loại này nên được giải phóng sau khi dùng để tránh Excel crash. Vả lại, ADO cũng có thể khóa đường nối với CSDL cho nên việc giải phóng là rất nên.


Giết lầm hơn bỏ sót là chính sách của Tào Tháo, làm chính trị thì được nhưng không thể áp dụng cho lập trình.
Đối với lập trình, lầm và sót đều là sai.

Phương án "cứ để cho máy tính tự lo liệu" đại trà như vậy là sai.
Như tôi đã trình bày rõ rệt ở bài trước, có lẽ bạn may mắn là các objects của bạn đều được dựng theo biến nội. Gặp một mớ biến toàn cục mà không giải phóng chạy một hồi nó ì ạch luôn.
Anh cho em hỏi nếu chạy ì ạch, khi tắt excel đi và mở lại thì còn ì ạch không ạ. Và cần thiết khi khởi động lại máy tính thì còn hiện tượng ì ạch không ạ
Em cảm ơn, em là dân ngoại đạo nhưng vì em đam mê lập trình quá nên cũng muốn mở mang kiến thức ạ. Cảm ơn anh
Rất may cho bạn là biến toàn cục dùng bộ nhớ ụ (heap memory), lớn rất nhiều so với biến nội dùng bộ nhớ ngăn xếp (stack). Tuy nhiên, tài nguyên không chỉ riêng là bộ nhớ. Tài nguyên có loại riêng (của riêng chương trình, máy của bạn); nhưng cũng có loại chung như cổng kết nối, máy in,...
Bộ nhớ heap memory là gì ạ?
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Back
Top Bottom