Out of memory somewhat reproducable
My app is huge with several hundred thousand lines of code.
From time to time I get the error "Out of memory".
I have been able to somewhat reproduce it.
I have uploaded a video here:
https://youtu.be/iIZT-WisctY
If anybody has any idea what I could check, please let me know.
Thank you!
Edit: Updated video link as YT for some reason blocked it.
Re: Out of memory somewhat reproducable
Quote:
Originally Posted by
tmighty2
My app is huge with several hundred thousand lines of code.
Could it be that, perchance?
Does 100% of the code need to be in the app, or can some of it be put into DLLs to be called from the main app on-demand?
VB6 has a limited amount of memory space available, being a 32-bit system, and you need to be creative and strict about your variables to keep them and the code within that limitation
Re: Out of memory somewhat reproducable
Not the best solution, but you could make the VB6 IDE /LARGEADDRESSAWARE by using EDITBIN.EXE
You could also make your compiled .EXE LargeAddressAware by adding;
Code:
[VBCompiler]
LinkSwitches=/LARGEADDRESSAWARE
...to your projects .VBP file.
Out of Memory - Ref: https://www.vbforums.com/showthread....=1#post5626457
LARGEADDRESSAWARE - Ref: https://www.vbforums.com/showthread....=1#post5626457
Joe
Re: Out of memory somewhat reproducable
Personally, I think you should be looking at data you're reading into memory. You'd be very surprised at how tightly VB6 code compiles into machine language. But large arrays (Collections, Dictionaries, etc) can easily blow up memory.
Also, just other thoughts, be sure you actually are compiling to machine code, and not p-code.
Does your program compile and run in the IDE? If so, that's more evidence that it's not the amount of code you have, as it'll take much more memory to run in the IDE than it would take as a machine code compiled EXE. When loading/running in the IDE, you're still limited to 2GB, including the IDE itself, and all the compiled p-code (which is what it is) when you execute from the IDE.
Another thought is that it might be some kind of recursion-gone-wild problem, but I believe that always reports an "out of stack space" error.
Also, it's possible you're doing some kind of memory manipulation with APIs, and not doing it correctly. That could also easily blow up your memory.
------------
Regarding LAA, I'm not a fan. I know that a couple of people here use it, but any piece of code (your memory pointer code, third-party OCXs or DLLs) that don't correctly handle memory pointers, could hard-crash your program with LAA.
The "shuttle code to ActiveX DLLs" is a good idea, but, if you do that, you need to make sure there are chunks of code that you can load, and then unload when done, for that to be useful. If all of your code needs to be in memory at the same time, then ActiveX DLLs will actually be a hindrance.
------------
p.s. My primary application is also 100s of 1000s of lines of code, and I've got no memory problems at all. However, for the primary data storage, I use an MDB database, and the DAO to manipulate it. I'll occasionally have 20 or more tables open, but seldom will I actually read much data into memory. During various processing, I might read large ASCII files into memory in their entirety, but an ASCII file would have to be really large to make much of a dent on 2GB.
Just as a further FYI, on a 64-bit Windows machine (which most everything is these days) with any decent amount of memory in it (say, 8GB or more), we do get a full 2GB of memory for our VB6 program.
1 Attachment(s)
Re: Out of memory somewhat reproducable
Quote:
Originally Posted by
tmighty2
Attachment 190313
This video is no longer available because the account was closed.
What's going on, tmighty2?
Re: Out of memory somewhat reproducable
Thank you for the hint.
Not sure why that happened.
Here is a new link:
https://youtu.be/iIZT-WisctY
Re: Out of memory somewhat reproducable
You have an out of memory in the IDE, wow
When you open the task manager, how much memory does VB6 use?
How large are your modules? I believe there is a maximum for the number of characters a single module can have.
Do you get the same Out of memory error when you edit the code without having started the project first?
How much memory is used by VB6 when you only open your project?
How memory is used when the project is started?
How much memory is used when you return to the IDE?
3 Attachment(s)
Re: Out of memory somewhat reproducable
Attachment 190319
79.4 MB when I open up the project in VB6.
350 MB when I run the app in the IDE.
Attachment 190323
Attachment 190324
Re: Out of memory somewhat reproducable
That generic "out of memory" VB6 error is a bit misleading because it encompasses many limited resources that are not literally "memory". And sometimes limited by a registry setting and not the actual hardware.
Re: Out of memory somewhat reproducable
I have removed the reference to msxml6.dll and use CreateObject, and the error is gone.
I have readded it, and so far, the error is still gone.
If anybody has any idea how to debug this, please tell me.
Re: Out of memory somewhat reproducable
Quote:
Originally Posted by
tmighty2
I have removed the reference to msxml6.dll and use CreateObject, and the error is gone.
I have readded it, and so far, the error is still gone.
If anybody has any idea how to debug this, please tell me.
The error you get in the Youtube clip is a VB6 IDE error, how do you want to debug the IDE itself :confused:
Re: Out of memory somewhat reproducable
The first thing I always notice that is VB6 does is to jump to a line using something like this:
Code:
Dim s$
s = Command() ' IDE jumps here with "Out of memory"
It usually happens with functions like:
I noticed I kept mixing up the $ vs. non-$ variants of string functions. I thought this might cause headaches for the compiler, so I tried to always use the correct $ variant. But even after fixing them many times, I would keep slipping back into using the wrong one when writing new code.
To reduce mistakes (and see if it could help avoid Out of memory), I added safeguards: I block the unsafe calls and force myself to use wrapper functions with a …2 suffix instead. Example:
Code:
Public Function Left2(ByVal uString As String, ByVal uLength As Long) As String
Left2 = VBA.Left$(uString, uLength)
End Function
Public Sub Left()
' safeguard: prevent direct use, must call Left2()
Debug.Assert False
End Sub
With TwinBasic I can now also locate lines that VB6 could not show before due to "Out of memory", for example:
Code:
u = Replace(u, ChrW$(34), "")
So I expanded this safeguard approach to many functions — each blocked with a Sub, plus a corresponding wrapper function that always calls the $ variant. For example:
Code:
Public Function Left2(ByVal uString As String, ByVal uLength As Long) As String
Left2 = VBA.Left$(uString, uLength)
End Function
Public Sub Left()
' safeguard: prevent direct use, must call Left2()
Debug.Assert False
End Sub
So I expanded this safeguard approach to many functions — each blocked with a Sub, plus a corresponding wrapper function that always calls the $ variant. For example:
Code:
Public Sub ChrW()
' safeguard: must use ChrW2()
Debug.Assert False
End Sub
Public Function ChrW2(ByVal CharCode As Long) As String
ChrW2 = VBA.ChrW$(CharCode)
End Function
Public Sub Command()
' safeguard: must use Command2()
Debug.Assert False
End Sub
Public Function Command2() As String
Command2 = VBA.Command$()
End Function
Public Sub CurDir()
' safeguard: must use CurDir2()
Debug.Assert False
End Sub
Public Function CurDir2(Optional Drive As String) As String
CurDir2 = VBA.CurDir$(Drive)
End Function
Public Sub Dir()
' safeguard: must use Dir2()
Debug.Assert False
End Sub
Public Function Dir2(Optional Pathname As String, Optional Attributes As VbFileAttribute = vbNormal) As String
Dir2 = VBA.Dir$(Pathname, Attributes)
End Function
Public Sub Environ()
' safeguard: must use Environ2()
Debug.Assert False
End Sub
Public Function Environ2(ByVal Name As String) As String
Environ2 = VBA.Environ$(Name)
End Function
Public Sub Format()
' safeguard: must use Format2()
Debug.Assert False
End Sub
Public Function Format2(ByVal Expression As Variant, Optional ByVal Style As String) As String
Format2 = VBA.Format$(Expression, Style)
End Function
Public Sub FormatCurrency()
' safeguard: must use FormatCurrency2()
Debug.Assert False
End Sub
Public Function FormatCurrency2(ByVal Expression As Variant, Optional NumDigitsAfterDecimal As Integer = -1, Optional IncludeLeadingDigit As VbTriState = vbUseDefault, Optional UseParensForNegativeNumbers As VbTriState = vbUseDefault, Optional GroupDigits As VbTriState = vbUseDefault) As String
FormatCurrency2 = VBA.FormatCurrency$(Expression, NumDigitsAfterDecimal, IncludeLeadingDigit, UseParensForNegativeNumbers, GroupDigits)
End Function
Public Sub Hex()
' safeguard: must use Hex2()
Debug.Assert False
End Sub
Public Function Hex2(ByVal Number As Variant) As String
Hex2 = VBA.Hex$(Number)
End Function
Public Sub LCase()
' safeguard: must use LCase2()
Debug.Assert False
End Sub
Public Function LCase2(ByVal uString As String) As String
LCase2 = VBA.LCase$(uString)
End Function
Public Sub Left()
' safeguard: must use Left2()
Debug.Assert False
End Sub
Public Function Left2(ByVal uString As String, ByVal uLength As Long) As String
Left2 = VBA.Left$(uString, uLength)
End Function
Public Sub Mid()
' safeguard: must use Mid2()
Debug.Assert False
End Sub
Public Function Mid2(ByVal uString As String, ByVal uStart As Long, Optional ByVal uLength As Long) As String
Mid2 = VBA.Mid$(uString, uStart, uLength)
End Function
Public Sub Right()
' safeguard: must use Right2()
Debug.Assert False
End Sub
Public Function Right2(ByVal uString As String, ByVal uLength As Long) As String
Right2 = VBA.Right$(uString, uLength)
End Function
Public Sub Trim()
' safeguard: must use Trim2()
Debug.Assert False
End Sub
Public Function Trim2(ByVal uString As String) As String
Trim2 = VBA.Trim$(uString)
End Function
Public Sub UCase()
' safeguard: must use UCase2()
Debug.Assert False
End Sub
Public Function UCase2(ByVal uString As String) As String
UCase2 = VBA.UCase$(uString)
End Function
Public Sub RTrim()
' safeguard: must use RTrim2()
Debug.Assert False
End Sub
Public Function RTrim2(ByVal uString As String) As String
RTrim2 = VBA.RTrim$(uString)
End Function
Public Sub LTrim()
' safeguard: must use LTrim2()
Debug.Assert False
End Sub
Public Function LTrim2(ByVal uString As String) As String
LTrim2 = VBA.LTrim$(uString)
End Function
Public Sub Space()
' safeguard: must use Space2()
Debug.Assert False
End Sub
Public Function Space2(ByVal Number As Long) As String
Space2 = VBA.Space$(Number)
End Function
Public Sub Str()
' safeguard: must use Str2()
Debug.Assert False
End Sub
Public Function Str2(ByVal Number As Variant) As String
Str2 = VBA.Str$(Number)
End Function
Public Function String2(ByVal Number As Long, ByVal Character As Variant) As String
String2 = VBA.String$(Number, Character)
End Function
Public Function Chr2(ByVal CharCode As Long) As String
Chr2 = VBA.Chr$(CharCode)
End Function
A few functions (Input$, String$) can’t be safeguarded this way because their names cause conflicts.
If VB6 would not even jump to a specific line but would simply say "Out of memory", I would use TwinBasic.
TwinBasic would then show me a line like this:
With TwinBasic I can now also locate lines that VB6 could not show before due to "Out of memory", for example:
Code:
u = Replace(u, ChrW$(34), "")
That line would be not compilable because of the safeguard for ChrW().
Whether these safeguards completely prevent the "Out of memory" issue is unclear, but since that is I thing that the compiler jumps to at first, I had to tackle it.