Lập trình quản lý bộ nhớ thủ công quan trọng trong VBA (3 người xem)

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

HeSanbi

Nam Nhân✨Hiếu Lễ Nghĩa Trí Tín✨
Tham gia
24/2/13
Bài viết
2,897
Được thích
4,718
Giới tính
Nam
Bài viết này chia sẻ chuẩn hóa trong quản lý bộ nhớ cho VBA, giúp tối ưu mã để tránh gây quá tải bộ nhớ trong quá trình mã thực thi.

Tại sao cần quản lý bộ nhớ thủ công, mà không để cho VBA tự động dọn dẹp. Thực ra VBA có trình Runtime để dọn dẹp bộ nhớ, tuy nhiên vấn đề nằm ở cách trình dọn dẹp này hoạt động. Nếu như mã của bạn đang thực thi, bạn chủ quan không dọn dẹp, nghĩ rằng VBA tự động, nhưng tùy trường hợp VBA sẽ hẹn thời gian dọn dẹp, không phải dọn dẹp sau khi phương thức hoàn thành.


❌ Các lỗi thường mắc gây tốn kém bộ nhớ khi viết mã VBA​



1. Dùng mảng hoặc chuỗi quá lớn mà không xóa hoặc chia nhỏ.
Chuỗi và mảng trong VBA là hai dạng dữ liệu được cấp phát bộ nhớ không cố định như các kiểu số, logic.​
Chính vì vậy nếu dùng sai cách sẽ gây tốn kém bộ nhớ.​
❌ Tránh dùng​
JavaScript:
Sub test()
    Dim Arr
    Arr = [A1:Z1000]
    ...
End Sub

JavaScript:
Sub test()
    Dim Arr, s$
    s = String(1000000, "a")
    Arr = Split(STRConv(s,vbUnicode), vbNullChar)
End Sub

✅ Giải pháp​
JavaScript:
Sub test()
    Dim Arr
    Arr = [A1:Z1000]
    ...
    Erase Arr
End Sub

JavaScript:
Sub test()
    Dim Arr, s$
    s = String(1000000, "a")
    Arr = Split(STRConv(s,vbUnicode), vbNullChar)
    ...
    Erase Arr
    s = vbNullString
End Sub

2. Dùng chuỗi rỗng ("") trong thay thế và nối chuỗi.
Chuỗi rỗng, cần lưu ý chuỗi "" là chuỗi có tạo ra vùng nhớ nhưng độ dài là 0.​
vbNullString là một con trỏ Null (không trỏ đến chuỗi nào).​
❌ Tránh dùng​
JavaScript:
    For i = 1 To 10000
        Arr(i, 2) = Replace(Arr(i, 2), "a" , "")
    Next

JavaScript:
    s = JOIN(Arr, "")
✅ Giải pháp​
JavaScript:
    For i = 1 To 10000
        Arr(i, 2) = Replace(Arr(i, 2), "a" , vbNullString)
    Next
    Erase Arr

JavaScript:
    s = JOIN(Arr, vbNullString)
    ...
    s = vbNullString
3. Nối chuỗi dùng mảng
Nối chuỗi dùng mảng không gây vấn đề lớn nhưng vẫn nên tránh cho một số trường hợp​
❌ Tránh dùng​
JavaScript:
    Dim Arr, s$
    ReDim Arr(1 To 10000)
    For i = 1 To 1000
        Arr(i) = "a"
    Next
    s = JOIN(Arr, vbNullString)
✅ Giải pháp (Xem phần nâng cao)​

4. Dùng vòng lặp số duyệt qua thành phần, thay vì dùng For Each truy cập bộ nhớ
Vòng lặp For each trong VBA có thể khiến cho bộ nhớ của đối tượng không được giải phóng​
❌ Tránh dùng​
JavaScript:
    Dim ms As Object, m as Object
    Set Ms = regex.Execute("...")
    For Each m In Ms

    Next
    Set Ms = Nothing
    Set m = Nothing
✅ Giải pháp​
JavaScript:
    Dim ms As Object, m as Object, i&
    Set Ms = regex.Execute("...")
    For i = 0 To Ms.Count - 1
          Set m = Ms(i)
    Next
    Set Ms = Nothing
    Set m = Nothing
5. Dùng With nhưng thoát sớm không đi qua lệnh End With
Luôn luôn cho mã chạy qua End With trước khi rời khỏi​
❌ Tránh dùng​
JavaScript:
    Dim ms As Object, m as Object
    Set Ms = regex.Execute("...")
    With Ms
         If .Count = 0 Then Exit Sub
         ...
    End With
    Set Ms = Nothing
    Set m = Nothing
✅ Giải pháp​
JavaScript:
    Dim ms As Object, m as Object, i&
    Set Ms = regex.Execute("...")
    With Ms
         If .Count = 0 Then GoTo nWith
         ...
nWith:
    End With
    Set Ms = Nothing
    Set m = Nothing

6. Xử lý dữ liệu trực tiếp trên worksheet thay vì mảng

❌ Tránh dùng​
JavaScript:
       For i = 1 to 10000
            s = Range("A" & i").value
       Next
✅ Giải pháp​
JavaScript:
       Dim Arr
       Arr = Range("A1").Resize(10000).value
       For i = 1 to 10000
            s = Arr(i,1)
       Next
       Erase Arr
7. Gọi lệnh End giải phóng toàn bộ trạng thái về ban đầu

❌Tránh​
Gọi lệnh End khi đang thao tác bộ nhớ với các hàm win32 API, hoặc DLL đã được tải mà chưa được giải phóng.​
Nếu Callback Function (Gọi lại hàm bộ nhớ) như OnReadyStateChange của lớp MSXML2.XMLHTTP được khởi tạo và chạy nhưng chưa trả về.​
✅ Giải pháp​
Gọi lệnh End khi đã giải phóng các bộ nhớ liên quan do Lớp và Win32 API khởi tạo.​

Tóm lại​

Luôn giải phóng tài nguyên, chọn kiểu dữ liệu tối ưu, và xử lý dữ liệu theo từng phần.​
  • Với chuỗi và mảng: dùng Erase, Empty, hoặc "".
  • Với đối tượng (Excel/Access): luôn Close và Set ... = Nothing.
  • Với vòng lặp lớn: tái sử dụng biến, tránh tạo mới liên tục.

✅ Phương pháp lập trình nâng cao​



1. Nối chuỗi xử lý chuỗi dùng hàm MID
Cấp phát bộ nhớ cho một chuỗi với độ dài cần thiết, sau khi gán với hàm MID xong, cần cắt cho bằng với độ dài cần thiết.​
Điều này không gây cấp phát bộ nhớ lặp đi lặp lại nếu dùng toán tử nối chuỗi (&).​
*Chú ý: Hàm MID vẫn gây ra lỗi bộ nhớ nếu sử dụng quá tải trong một số trường hợp xử lý ký tự Unicode.​

JavaScript:
Sub BuildString()
    Dim s As String, i As Long, pos As Long
  
    ' Giả sử cần tạo chuỗi gồm 10000 lần "abc"
    Dim n As Long
    n = 10000
  
    ' Cấp phát trước bộ nhớ cho chuỗi (3 ký tự * 10000 = 30000)
    s = String$(n * 3, " ")   ' tạo chuỗi dài toàn khoảng trắng
  
    pos = 1
    For i = 1 To n
        Mid$(s, pos, 3) = "abc"
        pos = pos + 3
    Next i
  
End Sub

2. Dùng Win32 API thay cho hàm Mid và ASCW để lấy mã Unicode nếu xử lý chuỗi lớn
Trong vòng lặp lớn để lấy mã Unicode của ký tự với Mid và ASCW sẽ gây mã chạy chậm.​
Hãy dùng Win32 API sau để thực hiện:​
JavaScript:
#If VBA7 Then
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal length As LongPtr)
#Else
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
#End If

Private Sub StringToIntegers(ByVal s As String, refArr() As Integer, Optional BaseArray& = 0)
  Dim l As Long
  l = Len(s): If l = 0 Then Exit Sub
  ReDim refArr(BaseArray To l + BaseArray - 1) As Integer
  CopyMemory ByVal VarPtr(refArr(BaseArray)), ByVal StrPtr(s), l * 2
End Sub

Hướng dẫn trên đây giúp các bạn phòng tránh rủi ro về bộ nhớ trong lập trình VBA. Điều này rất quan trọng, vì bộ nhớ là có giới hạn, lập trình quản lý bộ nhớ tốt sẽ giúp ứng dụng chạy mượt hơn, an toàn hơn.
Đồng thời tránh rủi ro cho người sử dụng.

Xem thêm bài viết:
VBA Nâng cao: các lỗi viết mã và cách tránh lỗi ứng dụng bị xem là có virus

Tham khảo thêm các bài viết về vba nâng cao tại tag #vba nâng cao
 
Lần chỉnh sửa cuối:

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

Back
Top Bottom