Solved

ReDim Preserve Problem!

Posted on 2002-03-05
17
1,019 Views
Last Modified: 2008-03-10
Hi,

In declaring an array like this:

Dim TempArray() As String

TempArray(10) As String

Then, I want to make the array larger without removing the current content.

ReDim Preserve TempArray(15)

Could anyone teach me how will the memory be allocated?

I think a new memory area will be allocated to save this array. Am I Right?

If yes, how about the memory allocated when I declared the size of the array is 10 before.
Will this memory deallocate immediately after resize the array by "ReDim Preserve...."

Thank you!

0
Comment
Question by:cplau
  • 9
  • 5
  • 2
  • +1
17 Comments
 
LVL 17

Expert Comment

by:inthedark
ID: 6843669
Yes but the old memory is released.

So it is frequently suggested that you reduces redimensions as fara as possible.


For example:

Redim MyArray(100) as String

DO While Not Complete
    C=c+1
    if C>Ubound(MyArray) Then
        Redim Preserve MyArray(c+500) ' add an extra amount to reduce redimenesions
    End If

    ' Some Processing
Loop
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6843695
You can prety well ignore memory issues with ReDim but here are some tips:

In a Form Declaration Put the following:

Dim MyArray() As SomeType' Leave empty brackets

BEFORE you use the array you must create some elements.

Redim MyArray(10) ' no need for type

Redim Preserve MyArray(5) ' Can go down or Up

Warning multidemensional arrays have restrictions:

Redim MyArray(10,20)

'Ubound(MyArray,1) will now equal 10
'Ubound(MyArray,2) will now equal 20

Redim Preserve MyArray(10,30) ' ok to redimension the outer element only

Redim Preserve MyArray(5,30) ' Will cause an error.

User defined types offer a fantastic speed increase instead of using collections of classes.

Warning there are some bugs in VB 6 when redimensioning User Defined Types UDT's.

Example:

Private Type MyType
  Fred as String
  Jim as Long
End Type

Dim MyVar() as MyType

Private Form_Load()
    Redim MyVar(10)  
End Sub

Sub Command1_Click()

Call MySub(MyVar(1).Jim) ' This will get you into trouble if you redim the UDT

Redim Reserve MyVar(100) ' you may get an error

End Sub

To fix the problem with user defined types, decare the type global from withing a module (if necessary) and change the code as follows:

Sub Command1_Click()

Call MySub(1) ' Just pass the element

Redim Reserve MyVar(100) ' Will now work

End Sub

Sub MySub(El as long)
  MyLong=MyVar(EL).Jim
End Sub


0
 
LVL 17

Expert Comment

by:inthedark
ID: 6843703
I forgot, when you finish using an Array you can release the resouce help by the array as follows:


Option Explicit
Dim MySharedArray() as String

Private Sub Command1_Click

Redim MyPrivateArray(20)

Redim MySharedArray(200)
' some more processing
Redim Preserve MySharedArray(300)

' release the resouces but this array can't be reused
' until is is redimensioned.
Erase MySharedArray

' This line is not required
Erase MyPrivateArray

' As MyPrivateArray is only used in Command1_Click, it will go out of scope and will be automatically released after the End or Exit Sub

End Sub
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6843809
Description of the UDT redimension problem when exiting a loop within a With satetment:

http://www.google.com/search?q=cache:XGKKAkwW8DQC:www.buygold.net/v01n07/v01n07.html+redim+preserve+udt+locked&hl=en
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6843818
Further UDT redim problems:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;q187553

Please get back if you need any more specifc help.
0
 
LVL 2

Expert Comment

by:Ixeus
ID: 6843842
It's very bad practice to not specify the type you're using when declaring an array, since it immediately assigns a variant to it, and depending on resources allocates a fairly significant amount of memory depending on array size.  Always try to give as much info as you can when declaring variables.

Even if it's just 1 element.
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6843981
Good point Ixeus, also deined variabled work about 20% faster.

Private Sub Command1_Click()

Dim t As Single

Dim lc As Long
Dim v

' loop for one second using a variant
t = timer
Do
    v = v + 1
    If timer - t > 1 Then Exit Do
Loop

' and now with a long
t = timer
Do
    lc = lc + 1
    If timer - t > 1 Then Exit Do
Loop
   
MsgBox "Score Long: " + CStr(lc) + "   Variant: " + CStr(v) + " % dif: " + Format(100 * (lc - v) / v, "0.00")


End Sub
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6843985
sorry for typo:

Good point Ixeus, also defined variables work about 20% faster than variants.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 18

Expert Comment

by:mdougan
ID: 6844892
Correcting one thing inthedark said (I think we've had this discussion before inthedark ;)  )

' no elements have been created in memory
Dim TempArray() As String

' 11 elements have been created in memory
Redim TempArray(10) As String

' your first 11 are still in memory along with 5 more
' the contents of the first 11 are preserved
ReDim Preserve TempArray(15) as String

' temp array is still taking up 16 elements in memory
' but only the first 6 are addressable and they have
' been cleared out
Redim TempArray(5) as String

' no elements are held in memory
Erase TempArray

So, you can redim an array downwards but it will never free up the memory until you erase it.  If this is a problem, all you can do is copy the contents to another array, then erase the original array and re-dim it, and then copy the contents back in.
0
 

Author Comment

by:cplau
ID: 6845943
Dear inthedark,

do you mean that the old memory will not be released?

i.e

Redim MyArray(10) As String
' 11 elements will hold at memory

ReDim Preserve MyArray(20) as String
' 21 elements will hold at memory + 11 elemets hold at old memory

Am I correct?

Thank you!
0
 
LVL 18

Expert Comment

by:mdougan
ID: 6846223
Redim MyArray(10) As String
' 11 elements will hold at memory

MyArray(4) = "Hello"
MyArray(5) = "World"

ReDim Preserve MyArray(20) as String
' 21 elements will hold at memory + 11 elemets hold at old memory

' This will display Hello World
Msgbox MyArray(4) & " " & MyArray(5)

It's as I said, when you specify Redim Preserve, the contents of your array are preserved.  When you specify Redim, the addressable size of your array is moved up or down but if you dimension down (make the array smaller) you are not actually freeing up memory.  Only when you issue an Erase will you free up the memory.

If you Did this:

Redim MyArray(10) As String
' 11 elements will hold at memory

MyArray(4) = "Hello"
MyArray(5) = "World"

ReDim MyArray(20) as String
' 21 elements will hold at memory

' This will display nothing
Msgbox MyArray(4) & " " & MyArray(5)
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6846612
mdougan, I am always prepared to beleive that I have misunderstood Microsoft's product documentation,  my greek is not very good and double dutch is even worse. But if you are right and I am wrong how to you explain the following?

1) Paste the following code into a new project's form1 declarations.
2) On NT or Windows 2000 open the "Task Manager" and click on the "Performance" tag.  
3) Run the code
4) Make a note of the Available Physical memory.
5) Click on command1 which should reduce the Available memory.
6) Click on command2 you will note that Available memory almost goes back to where it was.

If you are using Windows 95/98/Milenium you can use MS Word About "Sys Info" to find the current Available Memory.

I suspect that in conclusion Redim Preserve will release memory if the elements an array are reduced.

Option Explicit

Dim Jim() As Long
Private Sub Command1_Click()
' Take a chunk of memory
ReDim Preserve Jim(1000000)
Dim c As Long
' and use it just for good measure
For c = 0 To 1000000
Jim(c) = c
Next c
msgbox "Memory has been allocated"
End Sub

Private Sub Command2_Click()
ReDim Preserve Jim(0)
End Sub

Private Sub Command3_Click()
Erase Jim
End Sub
0
 
LVL 18

Expert Comment

by:mdougan
ID: 6849688
I'm sure that you are seeing the memory being deallocated.  That is not the issue.  The issue is whether you, as the programmer, was in control of that deallocation, or whether some garbage collection routine in VB decided to deallocate the resources.  Yes, if you allocate a huge array, and then stop using most of the elements, VB MIGHT decide to deallocate the memory.  Or, you can issue the ERASE statement and ensure that it is deallocated.  It's up to you.  

Here is just one of Microsoft's pages on the subject:

Visual Basic Language Reference  

Erase Statement
Used to release array variables and deallocate the memory used for their elements. (this is pretty easy to understand isn't it ;)   )

Erase arraylist
Parts
arraylist
Required. List of array variables to be erased. Multiple variables are separated by commas.
Remarks
The Erase statement can appear only at procedure level. This means you can release arrays inside a procedure but not at class or module level.

The Erase statement is equivalent to assigning Nothing to each array variable.

Example
This example uses the Erase statement to clear two arrays and free their memory (1000 and 100 storage elements respectively). The ReDim statement then assigns a new array instance to the three-dimensional array.

Dim Int3DArray(9, 9, 9), Int2DArray(9, 9) As Integer
' ...
Erase Int3DArray, Int2DArray
' ...
ReDim Int3DArray(4, 4, 9)
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6849805
The point is that the memory becomes marked as available and your right that it won't be actually available until after the next garbage collection.  But if the memory becomes full the garbage collection will be performed automatically.  You are not in control of garbage collection becuase for best efficiency the process is managed internally so when the event manager detectes idle time the garbage collection is fired. But your right in a proces that does not yeild the VB memory pool will become very scrappy but if you right lots of loops with no doevents you deserve to get screwed.

But in real life normally things are added to dynamic arrays and the size seldom reduces, until the subroutine goes out of scope and all of the memory is returned. But if you are in subroutine which maintains a continuous loop it may be wise to follow a redim preserve with a doevents statement.  And to be nice to other processes running on your pc you must scatter doevents within all loops.

0
 
LVL 18

Expert Comment

by:mdougan
ID: 6851926
I think we're finally in agreement ;)
0
 

Author Comment

by:cplau
ID: 6855253
Hi All,

How will the memory be handled in this case:

Dim OneArray() As String
Dim TwoArray() As String

ReDim OneArray(100)
' 101 elements will be allocated
ReDim TwoArray(10)
' 11 elements will be allocated

OneArray(0) = "111"
OneArray(1) = "222"
OneArray(2) = "333"
OneArray(3) = "444"
OneArray(4) = "555"
TwoArray(0) = "!!!!"

OneArray = TwoArray

I found OneArray will only contain 11 elements now.

How about the 101 elements allocated before?
Will it be deallocated immediately after running
OneArray = TwoArray?

Thanks

0
 
LVL 18

Accepted Solution

by:
mdougan earned 100 total points
ID: 6855311
By saying OneArray = TwoArray, you simply put the address of the array of 11 elements into OneArray.  I think you might find that if you do this:


OneArray = TwoArray

TwoArray(1) = "XXXXX"
Msgbox OneArray(1)

That you'll see that updating TwoArray will also affect OneArray.

The 101 elements from the original OneArray will be marked for garbage collection, but will not be immediately deallocated (it's up to VB when to do this).

A better technique might be:

Dim OneArray() As String
Dim TwoArray() As String

ReDim OneArray(100)
' 101 elements will be allocated
ReDim TwoArray(10)
' 11 elements will be allocated

OneArray(0) = "111"
OneArray(1) = "222"
OneArray(2) = "333"
OneArray(3) = "444"
OneArray(4) = "555"
TwoArray(0) = "!!!!"

Erase OneArray
OneArray = TwoArray
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now