The credit card processing service Authorize.net is currently down. Please use Paypal or Amazon Payments on check out or try back soon!
0

memory leak with adafruit_matrixportal and/or PortalBase
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

memory leak with adafruit_matrixportal and/or PortalBase

by grookill on Wed Mar 10, 2021 12:56 am

I've been working on a clock/news scroller similar to the code in https://learn.adafruit.com/matrix-portal-new-guide-scroller. I have my own JSON server that I use to consolidate different news sources and then will present a standardized data stream (headlines) to systems that ask.

I ran into memory issues and started to chase it down. It appears that "matrixportal.set_text" leaks memory and eventually will cause a crash. The workaround is to use gc.mem_free() after "set_text" but the problem in "set_text" really should be resolved.

I created a test script (which can be found at the end) and came up with these results:

Adafruit CircuitPython 6.2.0-beta.3 on 2021-03-04; Adafruit Matrix Portal M4 with samd51j19

With gc.collect()

code.py output:
free mem: 50432
loop: 1 at beggining of loop free mem: 44416
after first gc.collect free mem: 44432
before first set_text free mem: 44432
before second set_text free mem: 43440
before scroll_text free mem: 37824
at end of loop free mem: 37824
...
...
loop: 100 at beggining of loop free mem: 35632
after first gc.collect free mem: 35632
before first set_text free mem: 35632
before second set_text free mem: 35632
before scroll_text free mem: 34656
at end of loop free mem: 34656
Start: 44416 End: 34656 Diff: -9760




Without gc.collect:
code.py output:
free mem: 50528
loop: 1 at beggining of loop free mem: 44416
after first gc.collect free mem: 44416
before first set_text free mem: 44416
before second set_text free mem: 40528
before scroll_text free mem: 13136
at end of loop free mem: 13136
...
...
after first gc.collect free mem: 1472
before first set_text free mem: 1472
before second set_text free mem: 33968
before scroll_text free mem: 1456
at end of loop free mem: 1456
loop: 75 at beggining of loop free mem: 1456
after first gc.collect free mem: 1456
before first set_text free mem: 1456
before second set_text free mem: 33008
Traceback (most recent call last):
File "code.py", line 64, in <module>
File "adafruit_portalbase/__init__.py", line 245, in set_text
File "adafruit_display_text/label.py", line 138, in __init__
File "adafruit_display_text/label.py", line 324, in _update_text
MemoryError: memory allocation failed, allocating 512 bytes


Code done running.
====================================================================================

Adafruit CircuitPython 6.1.0 on 2021-01-21; Adafruit Matrix Portal M4 with samd51j19

with gc.collect:

code.py output:
free mem: 51232
loop: 1 at beggining of loop free mem: 44400
after first gc.collect free mem: 44416
before first set_text free mem: 44416
before second set_text free mem: 43440
before scroll_text free mem: 37696
at end of loop free mem: 37696


loop: 99 at beggining of loop free mem: 36656
after first gc.collect free mem: 36656
before first set_text free mem: 36656
before second set_text free mem: 36656
before scroll_text free mem: 35600
at end of loop free mem: 35600
loop: 100 at beggining of loop free mem: 35600
after first gc.collect free mem: 35600
before first set_text free mem: 35600
before second set_text free mem: 35600
before scroll_text free mem: 34544
at end of loop free mem: 34544
Start: 44400 End: 34544 Diff: -9856

Without gc.collect:

code.py output:
free mem: 51232
loop: 1 at beggining of loop free mem: 44400
after first gc.collect free mem: 44400
before first set_text free mem: 44400
before second set_text free mem: 40528
before scroll_text free mem: 13008
at end of loop free mem: 13008
...
...
loop: 100 at beggining of loop free mem: 22704
after first gc.collect free mem: 22704
before first set_text free mem: 22704
before second set_text free mem: 18832
before scroll_text free mem: 2864
at end of loop free mem: 2864
Start: 44400 End: 2864 Diff: -41536


Test script:

Code: Select all | TOGGLE FULL SIZE
import time
import board
import terminalio
import json
import busio
import adafruit_pcf8523
from adafruit_matrixportal.matrixportal import MatrixPortal
import gc

print("free mem:", gc.mem_free())

myI2C = busio.I2C(board.SCL, board.SDA)
rtc = adafruit_pcf8523.PCF8523(myI2C)
now = rtc.datetime

DATA_SOURCE = ( "http://10.0.0.167:5000/space/articles" )
TITLE_DATA_LOCATION = ""
matrixportal = MatrixPortal(
    url=DATA_SOURCE,
    json_path=TITLE_DATA_LOCATION,
    status_neopixel=board.NEOPIXEL,
)

matrixportal.add_text(
    text_font=terminalio.FONT,
    text_position=((matrixportal.graphics.display.width // 2) - 15, 4),
    text_color=0x800000,
)

# Learn guide title (ID = 1)
matrixportal.add_text(
    text_font=terminalio.FONT,
    text_position=(2, 25),
    text_color=0x000080,
    scrolling = True
)


msgCount = 0
loopCount = 0
loopCountStartMem = 0
loopCountStartMem = 0
timeStr = "12:59"
msgList = ["a"*50,"b"*60,"c"*70,"d"*80,"e"*90,"f"*100]
gcCollect = False
while True:
    if loopCount == 0:
        loopCountStartMem = gc.mem_free()
    loopCount += 1
    print("loop:", loopCount, "  at beggining of loop free mem:", gc.mem_free())
    if gcCollect:
        gc.collect()
    print("after first gc.collect free mem:", gc.mem_free())
    if msgCount >= len(msgList):
        msgCount = 0
    msgString = msgList[msgCount]
    if gcCollect:
        gc.collect()
    print("    before  first set_text free mem:", gc.mem_free())
    matrixportal.set_text(timeStr,0)
    if gcCollect:
        gc.collect()
    print("    before second set_text free mem:", gc.mem_free())
    matrixportal.set_text(msgString,1)
    if gcCollect:
        gc.collect()
    print("      before scroll_text free mem:", gc.mem_free())
    matrixportal.scroll_text(0.0)
    if gcCollect:
        gc.collect()
    msgCount += 1
    if gcCollect:
        gc.collect()
    print("        at end of loop free mem:", gc.mem_free())
    if loopCount >= 100:
        loopCountEndMem = gc.mem_free()
        print("Start:", loopCountStartMem, " End: ", loopCountEndMem, " Diff: ", (loopCountEndMem - loopCountStartMem))
        loopCount = 0
        while True:
            pass
       
print("all done!")

grookill
 
Posts: 12
Joined: Sat Feb 02, 2019 4:25 am

Re: memory leak with adafruit_matrixportal and/or PortalBase

by mikeysklar on Wed Mar 10, 2021 6:58 pm

Wow, latest CircuitPython tested and a script to reproduce. Thanks for doing the heavy lifting. Would you mind opening a github issues and pasting in your findings into the github archive for this library?

https://github.com/adafruit/Adafruit_Ci ... tal/issues

mikeysklar
 
Posts: 4955
Joined: Mon Aug 01, 2016 8:10 pm

Re: memory leak with adafruit_matrixportal and/or PortalBase

by grookill on Wed Mar 10, 2021 9:11 pm

Done!

If I did it right, issue #70 is now open at https://github.com/adafruit/Adafruit_CircuitPython_MatrixPortal/issues

grookill
 
Posts: 12
Joined: Sat Feb 02, 2019 4:25 am

Re: memory leak with adafruit_matrixportal and/or PortalBase

by mikeysklar on Thu Mar 11, 2021 10:13 am

Awesome. Thank you so much for opening an issue and sharing your findings.

mikeysklar
 
Posts: 4955
Joined: Mon Aug 01, 2016 8:10 pm

Please be positive and constructive with your questions and comments.