Author Topic: Problem with _FREEIMAGE  (Read 3694 times)

0 Members and 1 Guest are viewing this topic.

Offline Juanjogomez

  • Forum Regular
  • Posts: 117
    • View Profile
Problem with _FREEIMAGE
« on: November 17, 2019, 03:42:56 pm »
Hi,

I'm doing a billing program and print the invoices using...

Page & = _NEWIMAGE (PageWidth, PageHeight, 256)
_DEST Page &

... I design the invoice and print the invoice with

    _PRINTIMAGE Page &

... and I release the memory with:

    _FREEIMAGE (Page &)

The problem is that the memory is not released completely and the program grows and grows with successive invoices until it fails.

Making a list of invoices, when it takes more than 50 pages the program already occupies more than 1.5 GB in memory and produces a "handle error"

It might not work well _FREEIMAGE?

Thanks

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Problem with _FREEIMAGE
« Reply #1 on: November 17, 2019, 03:47:26 pm »
You may need to move the DEST and SOURCE off the image before freeing it.  My memory is telling me that you can’t free an image that is currently in focus.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Juanjogomez

  • Forum Regular
  • Posts: 117
    • View Profile
Re: Problem with _FREEIMAGE
« Reply #2 on: November 18, 2019, 01:54:05 am »
I don't get it to work.

I tried to put

_PRINTIMAGE (Page &)

_FONT 16 'change to the QB64 default font to free it
_FREEFONT FontHandle
_DEST 0
_FREEIMAGE (Page &)

and the program continues to grow until it fails on page 58 because it has already reached 1.5 GB.

I have also tried to create only once the page at the beginning of the program and make

CLS, _RGB (256, 256, 256)

before each invoice, but the same thing happens.

Thanks

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Problem with _FREEIMAGE
« Reply #3 on: November 18, 2019, 02:01:40 am »
Can you share the actual program?  It’s hard to debug without the problem code at hand.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Juanjogomez

  • Forum Regular
  • Posts: 117
    • View Profile
Re: Problem with _FREEIMAGE
« Reply #4 on: November 18, 2019, 11:38:28 am »
Can you share the actual program?  It’s hard to debug without the problem code at hand.

Hi,
here I attach the code, which has been simplified as I have taken the access to the database.
What the program does is to print 150 identical invoices (just change the invoice number).

The program keeps getting bigger and from the 35thn invoice (aprox.) it already takes around 1 GB of RAM.

Here I also attach the JPGs which are used.

Code: QB64: [Select]
  1. tlincre = 150
  2. pag = 0
  3. DIM menvases$(18)
  4.  
  5. FOR facturas% = 1 TO tlincre
  6.     pag = pag + 1
  7.     COLOR 1, 7
  8.     LOCATE 10, 30: PRINT "             "
  9.     LOCATE 11, 30: PRINT " IMPRIMIENDO "
  10.     LOCATE 12, 30: PRINT USING "   Pag:###   "; pag
  11.     LOCATE 13, 30: PRINT "             "
  12.     COLOR 7, 0
  13.     venta$(0) = "1"
  14.     envas$(0) = "0": menv = 0
  15.     mfac$ = LTRIM$(STR$(facturas%))
  16.     mfac$ = STRING$(6 - LEN(mfac$), "0") + mfac$
  17.  
  18.     abono = 0: sitfac2 = 0: rappel = 0: trappel = 0
  19.     FOR n% = 1 TO 18
  20.         menvases$(n%) = ""
  21.     NEXT
  22.     REDIM SHARED RESULTADO(columns, 1) AS STRING
  23.  
  24.     op = 1
  25.     reimp = 1
  26.     tbole = 1: nbole = 1
  27.     tipocopia = 2
  28.     v = 1: a% = 1
  29.     DO
  30.         GOSUB 20000
  31.         v = v + 24
  32.         IF v > a% THEN EXIT DO
  33.         nbole = nbole + 1
  34.     LOOP
  35.  
  36.    
  37.  
  38. 20000 '------------------ RUTINA DE  IMPRESION --------------------------------
  39. FOR copias = 1 TO 2
  40.     IF tipocopia = 2 THEN copias = 2
  41.     PageScale = 10
  42.     PageHeight = 297 * PageScale 'A4 paper size is 210 X 297 mm
  43.     PageWidth = 210 * PageScale
  44.     Page& = _NEWIMAGE(PageWidth, PageHeight, 32)
  45.     _DEST Page&
  46.     CLS , _RGB(256, 256, 256)
  47.     source_handle = _LOADIMAGE("logo.jpg", 32)
  48.     _PUTIMAGE (0, 0), source_handle, Page&
  49.     source_handle = _LOADIMAGE("disenofactura6.jpg", 32)
  50.     _PUTIMAGE (0, 261), source_handle, Page&
  51.     'CursorPosY = 570
  52.     PointSize = 12
  53.     IF copias = 2 THEN
  54.         _DEST Page&
  55.         source_handle = _LOADIMAGE("copia.png", 32)
  56.         _PUTIMAGE (0, 1000), source_handle, Page&
  57.     END IF
  58.  
  59.     PointSize = 9
  60.     FontHeight = INT(PointSize * 0.3527 * PageScale)
  61.     FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
  62.     _FONT FontHandle
  63.  
  64.     CursorPosY = 438: CursorPosX = 42: text$ = "   N. de Factura   ": GOSUB PrintTextGris
  65.  
  66.     PointSize = 12
  67.     FontHeight = INT(PointSize * 0.3527 * PageScale)
  68.     FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
  69.     _FONT FontHandle
  70.  
  71.     CursorPosY = 326: CursorPosX = 70: text$ = "18/11/19": GOSUB PrintText
  72.     CursorPosY = 326: CursorPosX = 410: text$ = "12:25": GOSUB PrintText
  73.     CursorPosY = 475: CursorPosX = 95: text$ = mfac$: GOSUB PrintText
  74.     b$ = LTRIM$(STR$(tbole)): b$ = SPACE$(2 - LEN(b$)) + b$
  75.     a$ = LTRIM$(STR$(nbole)): a$ = "(" + SPACE$(2 - LEN(a$)) + a$ + "/" + b$ + ")"
  76.     CursorPosY = 475: CursorPosX = 400: text$ = a$: GOSUB PrintText
  77.  
  78.     CursorPosY = 330: CursorPosX = 680: text$ = "CLIENTE DE PRUEBA": GOSUB PrintText
  79.     CursorPosY = 330: CursorPosX = 1895: text$ = "0125": GOSUB PrintText
  80.     CursorPosY = 379: CursorPosX = 680: text$ = "C/la que sea, 2": GOSUB PrintText
  81.     CursorPosY = 426: CursorPosX = 680: text$ = "Sevilla": GOSUB PrintText
  82.     CursorPosY = 476: CursorPosX = 680: text$ = "Telefono: 902555555": GOSUB PrintText
  83.     CursorPosY = 660
  84.  
  85.     FOR n% = v TO v + 23
  86.         IF n% > a% THEN EXIT FOR
  87.         '--- Bultos
  88.         CursorPosX = 240: a$ = "2": CALL converprin(a$, 10): text$ = a$: GOSUB PrintTextNum
  89.         '--- Articulos
  90.         CursorPosX = 255: text$ = "PATATAS": GOSUB PrintText
  91.         '--- Trazabilidad
  92.         CursorPosX = 780: text$ = "1023589547": GOSUB PrintText
  93.         '--- K Bruto
  94.         CursorPosX = 1206: a$ = "10.25": CALL converprin(a$, 10): text$ = a$: GOSUB PrintTextNum
  95.         '--- K Tara
  96.         CursorPosX = 1413: a$ = "2": CALL converprin(a$, 9): text$ = a$: GOSUB PrintTextNum
  97.         '--- K Neto
  98.         CursorPosX = 1622: a$ = "8.25": CALL converprin(a$, 10): text$ = a$: GOSUB PrintTextNum
  99.         '--- Precio
  100.         CursorPosX = 1804: a$ = "1.3": CALL converprin(a$, 8): text$ = a$: GOSUB PrintTextNum
  101.         '--- Total
  102.         a = INT(8.25 * 1.3 * 100 + .5) / 100: a$ = LTRIM$(STR$(a))
  103.         CursorPosX = 2020: CALL converprin(a$, 10): text$ = a$: GOSUB PrintTextNum
  104.         CursorPosY = CursorPosY + 48
  105.     NEXT
  106.     CursorPosY = 1948: CursorPosX = 388: a$ = "10.73": CALL converprin(a$, 13): text$ = a$: GOSUB PrintTextNum
  107.     CursorPosY = 1995: CursorPosX = 388: a$ = "0": CALL converprin(a$, 13): text$ = a$: GOSUB PrintTextNum
  108.     CursorPosY = 2045: CursorPosX = 388: a$ = "0": CALL converprin(a$, 13): text$ = a$: GOSUB PrintTextNum
  109.     CursorPosY = 1948: CursorPosX = 560: a$ = "4": CALL converprin(a$, 5): text$ = a$: GOSUB PrintTextNum
  110.     CursorPosY = 1995: CursorPosX = 560: a$ = "12": CALL converprin(a$, 5): text$ = a$: GOSUB PrintTextNum
  111.     CursorPosY = 2045: CursorPosX = 560: a$ = "21": CALL converprin(a$, 5): text$ = a$: GOSUB PrintTextNum
  112.     CursorPosY = 1948: CursorPosX = 800: a$ = "0.43": CALL converprin(a$, 12): text$ = a$: GOSUB PrintTextNum
  113.     CursorPosY = 1995: CursorPosX = 800: a$ = "0": CALL converprin(a$, 12): text$ = a$: GOSUB PrintTextNum
  114.     CursorPosY = 2045: CursorPosX = 800: a$ = "0": CALL converprin(a$, 12): text$ = a$: GOSUB PrintTextNum
  115.     CursorPosY = 1948: CursorPosX = 970: a$ = "0.5": CALL converprin(a$, 5): text$ = a$: GOSUB PrintTextNum
  116.     CursorPosY = 1995: CursorPosX = 970: a$ = "1.4": CALL converprin(a$, 5): text$ = a$: GOSUB PrintTextNum
  117.     CursorPosY = 2045: CursorPosX = 970: a$ = "5.3": CALL converprin(a$, 5): text$ = a$: GOSUB PrintTextNum
  118.     CursorPosY = 1948: CursorPosX = 1212: a$ = "0.05": CALL converprin(a$, 12): text$ = a$: GOSUB PrintTextNum
  119.     CursorPosY = 1995: CursorPosX = 1212: a$ = "0": CALL converprin(a$, 12): text$ = a$: GOSUB PrintTextNum
  120.     CursorPosY = 2045: CursorPosX = 1212: a$ = "0": CALL converprin(a$, 12): text$ = a$: GOSUB PrintTextNum
  121.     CursorPosY = 1948: CursorPosX = 1380: a$ = "0": CALL converprin(a$, 5): text$ = a$: GOSUB PrintTextNumGris
  122.     CursorPosY = 1948: CursorPosX = 1585: a$ = "0": CALL converprin(a$, 10): text$ = a$: GOSUB PrintTextNumGris
  123.     CursorPosY = 2045: CursorPosX = 1340: text$ = " ": GOSUB PrintText
  124.  
  125.     PointSize = 15
  126.     FontHeight = INT(PointSize * 0.3527 * PageScale)
  127.     FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
  128.     _FONT FontHandle
  129.     a$ = "11.21": CALL converprin(a$, 13): text$ = a$ + " EU"
  130.  
  131.     CursorPosY = 1992: CursorPosX = 2019: GOSUB PrintTextNum
  132.  
  133.     PointSize = 12
  134.     FontHeight = INT(PointSize * 0.3527 * PageScale)
  135.     FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
  136.     _FONT FontHandle
  137.     menvases$(1) = "1"
  138.  
  139.     IF menvases$(1) <> "" THEN
  140.         source_handle = _LOADIMAGE("envases.jpg", 32)
  141.         _PUTIMAGE (0, 2250), source_handle, Page&
  142.         CursorPosY = 2295: CursorPosX = 230
  143.         text$ = "18/11/19": GOSUB PrintText
  144.         CursorPosY = 2350: CursorPosX = 230: text$ = mfac$: GOSUB PrintText
  145.         CursorPosY = 2405: CursorPosX = 230: text$ = "0125": GOSUB PrintText
  146.         CursorPosY = 2460: CursorPosX = 230: text$ = "CLIENTE DE PRUEBA": GOSUB PrintText
  147.  
  148.         PointSize = 15
  149.         FontHeight = INT(PointSize * 0.3527 * PageScale)
  150.         FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
  151.         _FONT FontHandle
  152.         a$ = "11.21": CALL converprin(a$, 13): text$ = a$ + " EU"
  153.         CursorPosY = 2535: CursorPosX = 1230: GOSUB PrintTextNumGris
  154.         CursorPosY = 2535: CursorPosX = 1229: GOSUB PrintTextNumGris
  155.         CursorPosY = 2535: CursorPosX = 1231: GOSUB PrintTextNumGris
  156.  
  157.         PointSize = 12
  158.         FontHeight = INT(PointSize * 0.3527 * PageScale)
  159.         FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
  160.         _FONT FontHandle
  161.  
  162.         CursorPosY = 2310
  163.         CursorPosX = 1486: a$ = "2": CALL converprin(a$, 8): a$ = LEFT$(a$, 5): text$ = a$: GOSUB PrintTextNum
  164.         CursorPosX = 1504: text$ = "BATEA": GOSUB PrintText
  165.         CursorPosX = 2010: a$ = "0": CALL converprin(a$, 8): text$ = a$: GOSUB PrintTextNum
  166.     ELSE
  167.         CursorPosX = 1380: text$ = "-----": GOSUB PrintText
  168.         CursorPosX = 1590: text$ = "----------": GOSUB PrintText
  169.         CursorPosX = 1870: text$ = "--------": GOSUB PrintText
  170.     END IF
  171.     CursorPosY = CursorPosY + 45
  172.  
  173.     CursorPosY = 2850: CursorPosX = 50
  174.     text$ = "   Fecha: 18/11/19  N.F.:" + nbol$ + " Cli.:0125 Imp.:"
  175.     a$ = LTRIM$(STR$(11.21)): CALL converprin(a$, 13): text$ = text$ + a$
  176.     GOSUB PrintText
  177.  
  178.     _PRINTIMAGE Page&
  179.     _FONT 16 'change to the QB64 default font to free it
  180.     _FREEFONT FontHandle
  181.     _DEST 0
  182.  
  183.     _FREEIMAGE Page&
  184.  
  185. NEXT copias
  186.  
  187.  
  188.  
  189. 20520 RETURN
  190.  
  191.  
  192. PrintText:
  193. COLOR _RGB(0, 0, 0), _RGBA(255, 255, 255, 255) 'RED text on clear black background
  194. 'COLOR 0, 15
  195. _PRINTSTRING (CursorPosX, CursorPosY), text$
  196. CursorPosX = CursorPosX + _PRINTWIDTH(text$)
  197. 'CursorPosY = CursorPosY + FontHeight 'adjust print position down
  198.  
  199. PrintTextNum:
  200. COLOR _RGB(0, 0, 0), _RGBA(255, 255, 255, 255) 'RED text on clear black background
  201. 'COLOR 0, 15
  202. _PRINTSTRING (CursorPosX - _PRINTWIDTH(text$), CursorPosY), text$
  203. CursorPosX = CursorPosX + 2 * _PRINTWIDTH(text$)
  204. 'CursorPosY = CursorPosY + FontHeight 'adjust print position down
  205.  
  206. PrintTextNumGris:
  207. 'COLOR _RGB(210, 210, 210), _RGBA(256, 256, 256, 256) 'texto gris con fondo blanco
  208. 'fondo$ = STRING$(LEN(text$), CHR$(219))
  209. '_PRINTSTRING (CursorPosX - _PRINTWIDTH(fondo$), CursorPosY), fondo$
  210. COLOR _RGB(0, 0, 0), _RGBA(210, 210, 210, 0) 'texto negro con fondo gris transparente
  211. _PRINTSTRING (CursorPosX - _PRINTWIDTH(text$), CursorPosY), text$
  212. 'CursorPosX = CursorPosX + 2 * _PRINTWIDTH(text$)
  213. 'CursorPosY = CursorPosY + FontHeight 'adjust print position down
  214.  
  215. PrintTextGris:
  216. COLOR _RGB(0, 0, 0), _RGBA(210, 210, 210, 0) 'texto negro con fondo gris transparente
  217. _PRINTSTRING (CursorPosX, CursorPosY), text$
  218. CursorPosX = CursorPosX + _PRINTWIDTH(text$)
  219. 'CursorPosY = CursorPosY + FontHeight 'adjust print position down
  220.  
  221. '-----------------------------------------------------------------------------------------------------------------------------
  222. '----------------------------------------------------------- RUTINAS ---------------------------------------------------------
  223. '-----------------------------------------------------------------------------------------------------------------------------
  224.  
  225.  
  226. SUB converprin (a$, b)
  227.     '----------------------------------------- CONVERTIR NUMERO CON SEPARADORES DE MILES  Y 2 DECIMALES -----------------------
  228.     IF VAL(a$) <> 0 THEN
  229.         c# = VAL(a$)
  230.         d# = c# * 100 + .5
  231.         a# = INT(d#)
  232.         a$ = LTRIM$(STR$(a#))
  233.         IF LEN(a$) = 1 THEN
  234.             a$ = "0.0" + a$
  235.         ELSEIF LEN(a$) = 2 THEN
  236.             IF VAL(a$) < 0 THEN
  237.                 a$ = "-0.0" + RIGHT$(a$, 1)
  238.             ELSE
  239.                 a$ = "0." + a$
  240.             END IF
  241.         ELSEIF LEN(a$) = 3 AND VAL(a$) < 0 THEN
  242.             a$ = "-0." + RIGHT$(a$, 2)
  243.         ELSE
  244.             a$ = LEFT$(a$, LEN(a$) - 2) + "." + RIGHT$(a$, 2)
  245.         END IF
  246.     ELSE
  247.         a$ = "0.00"
  248.     END IF
  249.     a = b - LEN(a$)
  250.     IF a > 0 THEN
  251.         a$ = SPACE$(a) + a$
  252.     END IF
  253.     IF LEN(a$) - 6 > 0 THEN
  254.         IF MID$(a$, LEN(a$) - 6, 1) <> " " AND MID$(a$, LEN(a$) - 6, 1) <> "-" THEN
  255.             a$ = LEFT$(a$, LEN(a$) - 6) + "," + MID$(a$, LEN(a$) - 5)
  256.             a$ = MID$(a$, 2): '--para quitar caracter que se ha generado por meter la coma
  257.         END IF
  258.     END IF
  259.     IF LEN(a$) - 10 > 0 THEN
  260.         IF MID$(a$, LEN(a$) - 10, 1) <> " " AND MID$(a$, LEN(a$) - 10, 1) <> "-" THEN
  261.             a$ = LEFT$(a$, LEN(a$) - 10) + "," + MID$(a$, LEN(a$) - 9)
  262.             a$ = MID$(a$, 2): '--para quitar caracter que se ha generado por meter la coma
  263.         END IF
  264.     END IF
  265.     IF LEN(a$) - 14 > 0 THEN
  266.         IF MID$(a$, LEN(a$) - 14, 1) <> " " AND MID$(a$, LEN(a$) - 14, 1) <> "-" THEN
  267.             a$ = LEFT$(a$, LEN(a$) - 14) + "," + MID$(a$, LEN(a$) - 13)
  268.             a$ = MID$(a$, 2): '--para quitar caracter que se ha generado por meter la coma
  269.         END IF
  270.     END IF
  271.  
  272.  


Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Problem with _FREEIMAGE
« Reply #5 on: November 18, 2019, 11:51:11 am »
Just looking at the start of the code, I can see the issue already.  Let me highlight a few problems:

Code: [Select]
    source_handle = _LOADIMAGE("logo.jpg", 32)
    _PUTIMAGE (0, 0), source_handle, Page&
    source_handle = _LOADIMAGE("disenofactura6.jpg", 32)
    _PUTIMAGE (0, 261), source_handle, Page&
    'CursorPosY = 570
    PointSize = 12
    IF copias = 2 THEN
        _DEST Page&
        source_handle = _LOADIMAGE("copia.png", 32)

How many times are you loading images here?

How many times are you freeing them?

When you do call _FREEIMAGE later, how is it supposed to free all those images whose handle you overwrote??


    source_handle = _LOADIMAGE("logo.jpg", 32)
    _PUTIMAGE (0, 0), source_handle, Page&
    _FREEIMAGE source_handle
    source_handle = _LOADIMAGE("disenofactura6.jpg", 32)
    _PUTIMAGE (0, 261), source_handle, Page&
    _FREEIMAGE source_handle
    'CursorPosY = 570
    PointSize = 12
    IF copias = 2 THEN
        _DEST Page&
        source_handle = _LOADIMAGE("copia.png", 32)



Just because you're repurposing the variable you used to store your image handle, that doesn't mean you freed that image.  Tell me what this would do:

Code: [Select]
source_handle = _LOADIMAGE("logo.jpg", 32)
source_handle = source_handle + 1
_FREEIMAGE source_handle

Our image handle might've been -10, but we changed our variable to make it -9, so either we just freed the wrong image, or else we simply did nothing as there was no image number -9 to free...

You have to free those images before you repurpose your variable, or else you're going to see that massive memory leak which you're describing in your code.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Juanjogomez

  • Forum Regular
  • Posts: 117
    • View Profile
Re: Problem with _FREEIMAGE
« Reply #6 on: November 18, 2019, 03:31:55 pm »
Thanks for your time.
I didn't know you had to free the memory after loading an image.
I have put a "_FREEIMAGE source_handle" after loading each of the images but the memory continues to increase with each invoice.
It will also have to be placed after each change of font type?

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Problem with _FREEIMAGE
« Reply #7 on: November 18, 2019, 03:50:24 pm »
Aye.  It’s the same issues here:


Code: [Select]
    FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
    _FONT FontHandle
 
    CursorPosY = 438: CursorPosX = 42: text$ = "   N. de Factura   ": GOSUB PrintTextGris
 
    PointSize = 12
    FontHeight = INT(PointSize * 0.3527 * PageScale)
    FontHandle = _LOADFONT("c:\windows\fonts\times.ttf", FontHeight)
    _FONT FontHandle

Once again, you’re loading fonts without freeing them, and this generates a memory leak for your program.  Be certain to free those fonts before repurposing that handle for a different one.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Juanjogomez

  • Forum Regular
  • Posts: 117
    • View Profile
Re: Problem with _FREEIMAGE
« Reply #8 on: November 19, 2019, 04:05:06 am »
Thank you so much for everything.
What I have done is to load the images and the fonts at the beginning of the program, and then use the handle when I need them.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Problem with _FREEIMAGE
« Reply #9 on: November 19, 2019, 04:38:54 am »
Thank you so much for everything.
What I have done is to load the images and the fonts at the beginning of the program, and then use the handle when I need them.

That's generally the best bet.  Unless you're going to allow the user to choose the font size, or have a wild variety of images which need to be swapped on and off the map repeatedly, it's usually a good idea to just load them once and then have them available whenever you need them in your program.  It reduces disk reads, prevents the occurrences of accidental memory leaks like you were experiencing, and improves performance time overall.

Unless my program is running into some sort of memory barrier, or doing something really odd with loading/swapping a ton of resources, I tend to just do as you say you're doing now: Load it once and then forget about it.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!