Free up memory for unwanted Structure

Windows specific forum
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Free up memory for unwanted Structure

Post by RichardL »

Hi,
I'm tidying up some loose ends in MicroGrid and got stuck with freeing the memory for a structure I have finished with.
This is not an end-of-program issue but something that could happen repeatedly in normal operation.

Using values from the structure I have freed up some bitmaps with FreeImage(), used ClearStructure() to get rid of the strings (and assume that the memory they occupied has been returned to the OS or a heap somewhere.) and now I want to free the memory allocated to the structure body itself.

Although the structure is quite small it is untidy to leave it allocated, but unwanted.

Does PB have a way of doing this? I'm probably just not looking in the right place :(

Best regards
RichardL
User avatar
Shield
Addict
Addict
Posts: 1021
Joined: Fri Jan 21, 2011 8:25 am
Location: 'stralia!
Contact:

Re: Free up memory for unwanted Structure

Post by Shield »

Structured variables allocated within procedure bodies cannot be freed manually because
they are allocated on the stack and will be destroyed automatically once the call ends.
The same goes for global variables, although not allocated on stack, their memory cannot be reclaimed.

Can you show an example that shows what you'd like to free?
Image
Blog: Why Does It Suck? (http://whydoesitsuck.com/)
"You can disagree with me as much as you want, but during this talk, by definition, anybody who disagrees is stupid and ugly."
- Linus Torvalds
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Free up memory for unwanted Structure

Post by RichardL »

@Shield,
It's a big program, so I've taken a pair of scissors to make an illustration... it does not run, but shows the idea.
I create a new Structure() as uGrid's are created and displayed. Often they are on child windows and are only transient (like a requester).
When the window is closed I want to get rid of the uGrid as well.

Please excuse any errors... done in haste!

Code: Select all

; This is a demo of what I'm trying to do... do not run me!
Procedure uGridGadget(GadNum.i,gX,Gy,width,height,ColTitles.s,RowCount,flags) ; Create a new MicroGrid 
  If GridCount > 1
    Redim uGrid(GridCount)        
  EndIf
  
  ; Create memory block for CELL data
  *P = AllocateMemory(SizeOf(uG) * ColCount * RowCount) 
  If *P = 0 : ProcedureReturn 0 : EndIf
  
  ; Save essential data of the new GRID
  With uGrid(GridCount)
    \GridWin         = GetActiveWindow()
    \GridCellPointer = *P
    \GridColCount    = ColCount
    \GridRowCount    = RowCount
    
    
    \GridBackImage = CreateImage(#PB_Any,\GridPixW+2,\GridPixH+2)  
    \GridDataImage = CreateImage(#PB_Any,\GridPixW+2,\GridPixH+2) 
    
    ; etc etc ... about 34 items
    
  EndWith
   
  GridCount + 1
EndProcedure
Until now I have created all the transient windows and manage their visibility with HideWindow(). I'm not too keen on this because it (1) is not a good general solution, (2) I have to allocate resources to items that may not get used and (3) I think it is untidy!

This is a first cut of what I'm trying to do. The code has never been run is incomplete and probably bugged... but again I think the intention is clear. I'm now wondering if the Redim() does what I want in this case... but this is not the only instance of the problem!

Code: Select all

Procedure uGridDeleteGrid(GadNum)                ; UNFINISHED - Work in progress - NOT TESTED
  Protected Gr,n,T,
  
  Gr = uGridGetGridIndex(GadNum)         ; Find index of uGrid in grid table
  If Gr =-1 : ProcedureReturn 0 : EndIf  ; Not found.
  
  ; Ensure associated canvas does not have focus
  ; ??? 
  
  ; Free resources 
  With uGrid(Gr)
    FreeImage(\GridBackImage)            ; Free bitmaps
    FreeImage(\GridDataImage)
    
    ; Free strings associated with every individual CELL
    *P = \GridCellPointer                ; Pointer to first CELL
    For T = 1  To \GridRowCount *  \GridColCount
      *CellDat.CELLOPTIONS = *P
      ClearStructure(*P,CELLOPTIONS)     ; String pointers =>0, Numbers => 0
      *P + SizeOf(uG)                    ; Pointer to next CELL
    Next
    
    FreeMemory(\GridCellPointer)         ; Free grid data memory
    FreeGadget(\GridPBNum)               ; Destroy CanvasGadet()
  EndWith
  ClearStructure(@uGrid(Gr),GRIDOPTIONS) ; Free any strings etc..
  
  ; Shuffle table shut... ???
  If Gr ???
    For n = Gr To GridCount - 1
      CopyStructure(@uGrid(n+1),@uGrid(n),GRIDOPTIONS)
    Next
  EndIf
  
  ; Eliminate the top item  
  If GridCount > 1                       ; Re-dim table one smaller
    GridCount - 1                        ; Decrease number of grids
    Redim uGrid(GridCount)               
  EndIf
   
EndProcedure
You can see the whole project if you search for uGrid on this site.
Cheers,
RichardL
User avatar
Shield
Addict
Addict
Posts: 1021
Joined: Fri Jan 21, 2011 8:25 am
Location: 'stralia!
Contact:

Re: Free up memory for unwanted Structure

Post by Shield »

I am not sure if I understand your question completely.
After checking the snippet I think you will have a memory leak when the same numbers / IDs
are used again since you don't check whether the ID has been used before creating a new
gadget. Is that what you mean?

I wouldn't use an array for storing gadgets, instead I'd just go the #PB_Any approach
and deal with pointers directly. It only has advantages in my opinion.

A possible solution for the management of resources that might not get used is a 'lazy' loading mechanism.
Basically don't load anything until you actually need the resources for the first time.
Image
Blog: Why Does It Suck? (http://whydoesitsuck.com/)
"You can disagree with me as much as you want, but during this talk, by definition, anybody who disagrees is stupid and ugly."
- Linus Torvalds
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Free up memory for unwanted Structure

Post by RichardL »

@Shield:
>> I am not sure if I understand your question completely.
My fault for not explaining it clearly enough, I guess.

So, forget the foregoing and try this:

Code: Select all

Structure MYSTRING
  Test1$
  Test2$
  Test3$
  Num.l
EndStructure

Now.MYSTRING

Now\Test1$ = "ABC"  ; A string with contents
Now\Test2$ = ""     ; A string that has zero length
                    ; Test3$ is not initialised.
Now\Num    = 123456 ; A numeric variable

; Lets see what the structure contains, before and after
; a call to ClearStructure()
For n = 0 To 1
  
  *p = PeekL(@Now)     : Debug "Point1 "+Str(*p)
  If *p : Debug "<"+PeekS(*p)+">" : EndIf
  
  *p = PeekL(@Now + 4) : Debug "Point2 "+Str(*p)
  If *p : Debug "<"+PeekS(*p)+">" : EndIf  
  
  *p = PeekL(@Now + 8) : Debug "Point3 "+Str(*p)
  If *p : Debug "<"+PeekS(*p)+">" : EndIf  
  
  *p = PeekL(@Now + 12) : Debug "Point4 "+Str(*p)
  
  If n = 0
    ClearStructure(@Now,MYSTRING) ; Clear out all the data
  EndIf
  
  Debug "---------------"
Next

Debug "Structure address is :"+Str(@Now)
Debug "Size is                     :"+Str(SizeOf(MYSTRING))+ " bytes"

; At this point the Now.MYSTRING has no data but still occupies some memory.
; QUESTION: How do I free up this memory?

; FreeMemory(@Now) ... Nope!

How do I get my 16 bytes back?
User avatar
Shield
Addict
Addict
Posts: 1021
Joined: Fri Jan 21, 2011 8:25 am
Location: 'stralia!
Contact:

Re: Free up memory for unwanted Structure

Post by Shield »

Alright. As I said, you cannot free this memory as it is globally allocated.
Global variables, even structured ones, are allocated in a special code segment (neither heap nor stack).
This only includes native types (values / pointers), strings are allocated on the heap (which you can free).

If you create "Now" within a procedure, the variable will be allocated on stack which you also cannot free manually
without dealing with stack pointers on ASM level.

Edit:
Of course when you allocate the space using AllocateMemory, arrays, LLs, etc., you can free it. :)
Image
Blog: Why Does It Suck? (http://whydoesitsuck.com/)
"You can disagree with me as much as you want, but during this talk, by definition, anybody who disagrees is stupid and ugly."
- Linus Torvalds
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Free up memory for unwanted Structure

Post by RichardL »

@Shield
So my question stands.
Fred
Administrator
Administrator
Posts: 18361
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Free up memory for unwanted Structure

Post by Fred »

Use a dynamic block if you want to free it:

Code: Select all

Structure MYSTRING
  Test1$
  Test2$
  Test3$
  Num.l
EndStructure

*Now.MYSTRING = AllocateMemory(SizeOf(MYSTRING))
InitializeStructure(*Now, MYSTRING)

*Now\Test1$ = "ABC"  ; A string with contents
*Now\Test2$ = ""     ; A string that has zero length
                    ; Test3$ is not initialised.
*Now\Num    = 123456 ; A numeric variable

; Lets see what the structure contains, before and after
; a call to ClearStructure()
For n = 0 To 1
 
  *p = PeekL(*Now)     : Debug "Point1 "+Str(*p)
  If *p : Debug "<"+PeekS(*p)+">" : EndIf
 
  *p = PeekL(*Now + 4) : Debug "Point2 "+Str(*p)
  If *p : Debug "<"+PeekS(*p)+">" : EndIf 
 
  *p = PeekL(*Now + 8) : Debug "Point3 "+Str(*p)
  If *p : Debug "<"+PeekS(*p)+">" : EndIf 
 
  *p = PeekL(*Now + 12) : Debug "Point4 "+Str(*p)
 
  If n = 0
    ClearStructure(*Now,MYSTRING) ; Clear out all the data
  EndIf
 
  Debug "---------------"
Next

Debug "Structure address is :"+Str(*Now)
Debug "Size is                     :"+Str(SizeOf(MYSTRING))+ " bytes"

; At this point the Now.MYSTRING has no data but still occupies some memory.
; QUESTION: How do I free up this memory?

ClearStructure(*Now, MYSTRING)
FreeMemory(*Now)
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Free up memory for unwanted Structure

Post by RichardL »

@Fred
Thank you for your reply. Understood :)
Now I need to scratch my head to see how to incorporate it into my project.
Sawdust alert!

RichardL
Fred
Administrator
Administrator
Posts: 18361
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Free up memory for unwanted Structure

Post by Fred »

To be honnest, I don't understand why you want to reclaim a global block, as you shouldn't have tons of them (unless you have tons of different named variables). As Shield said, local variables, array etc are automatically freed when leaving the procedure.
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: Free up memory for unwanted Structure

Post by BorisTheOld »

Fred wrote:To be honnest, I don't understand why you want to reclaim a global block.......
We use the dynamic allocation and destruction of structure data as the basis of our implementation of OOP.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Free up memory for unwanted Structure

Post by RichardL »

@Fred
@Boris
Sorry for the delay in replying, I have been tidying up the lab ahead of a meeting.

Exactly as Boris has put it!

In my application I Redim() an array of structures as temporary 'requesters' are created, used and then destroyed, which in my case includes entries with about 120 integer values, many of which are strings pointers and some are Image#'s. ClearStructure() gets rid of the strings from a requester I have finished with (and I hope frees up the string space) and all I'm left with is an empty structure of 120*4 bytes. That is what I want to get rid of!

(I suppose I could re-write the code to have a fixed number of structures (more than I'm ever likely to use) and it then becomes an Insert/Delete problem. This is heavier on memory which should not really worry me, after all what is a few KBytes in a computer nowadays when a few Gb of RAM are most likely available. I suppose my reticence to use this approach is a carry over from my 6502 programming days when I had to squeeze an editor with auto formatting, an assembler and a disassembler into 16K... I just 'hate' wasting memory! :D :D )

Best regards
RichardL
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: Free up memory for unwanted Structure

Post by BorisTheOld »

RichardL wrote:Exactly as Boris has put it!
Take a look at this example of how I use dynamic allocation of memory.

http://www.purebasic.fr/english/viewtop ... 40&t=57143

This technique is particularly useful with very large applications, such as business systems, where only a subset of windows might be in use at any given time. Application resources are created and destroyed as needed, rather than all of them being created when the program is loaded.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
Post Reply