Python memory leak

im having a problem with the below script where every time i call this function, it builds another Joulescope object takes up memory, and cannot delete the old one. Is there a way to create a single joulescope object that i can continuously use to to read from?

def GetPeakCurrent(): 
    ####################################################################
    #Goal: use Joulescope to measure current average after 10 sec,
    #       and convert to Peak Current!
    #
    # I_Peak = (I_avg / 0.0225) mA       ***0.0225 unless pulse width changes
    ####################################################################
    #READ FROM JOULESCOPE:
    print("read from joulescope:")
    time.sleep(0.1)
    with joulescope.scan_require_one(config='auto') as js:
        data = js.read(contiguous_duration=args.measure_time)
    I_avg, V_avg = np.mean(data, axis=0, dtype=np.float64)
    I_avg = I_avg*1000                                                                  #convert current to mA
    I_peak = round(I_avg / ((args.trigger_freq)*(args.pulse_width)/1000000000),3)       
    return I_peak

Hi @noggin and welcome to the forum!

I think that you are running into a python garbage collection issue. When I run a modified version of your code (args doesn’t exist in your example code), memory grows dramatically until it finally levels out. If you want to force python garbage collection, you can import gc and then call gc.collect(), perhaps right after each call to GetPeakCurrent.

However, you probably intend to just scan and open the Joulescope JS110 once. You can then pass the Joulescope instance to your GetPeakCurrent function. Then it can just call the Joulescope read method directly. You do want to surround the code that opens the Joulescope with try/catch (or a context manager) to close the Joulescope. If you don’t, then the Joulescope thread will remain running and your program will not exit gracefully.

You want something like:

def get_peak_current(js, args): 
    data = js.read(contiguous_duration=args.measure_time)
    I_avg, V_avg = np.mean(data, axis=0, dtype=np.float64)
    I_avg = I_avg*1000                                                                  #convert current to mA
    I_peak = round(I_avg / ((args.trigger_freq)*(args.pulse_width)/1000000000),3)       
    return I_peak

def run():
    args = ... get args ...
    with joulescope.scan_require_one(config='auto') as js:
        while run_my_program:
            ... do stuff ...
            get_peak_current(js, args)
            ... do stuff ...

Does this make sense?

Thank you for being so fast with the replay! i think this fixed my problem. i am still curious why the Joulescope resource is not closed after we leave the “with” statement. Can you provide any clarification on this?

Quick follow up question: i opened a python shell and ran “import joulescope” and then “joulescope --help” such as the documentation on your site stated. i got an error saying “typeError: bad operand type for unary -: ‘_Helper’”. any idea what could be causing this?

The Joulescope is closed and resources released when the code leaves that with statement. The standard cpython implementation uses reference counting to free quickly. It is likely that the joulescope device instance contains a circular reference, which prevents it from being freed quickly. Calling gc.collect() forces the garbage collector to run sooner rather than later. We have some significant changes coming to the driver in the next few months, and we should be able to make changes to fix this.

I think there are two problems here. First, the joulescope command is not from within python, but from the command line. Also, the command should not be joulescope --help. It should be joulescope help. Thank you for pointing this out, and I just fixed the docs!

ahhhh i see now. that was a rookie mistake! haha thank you so much for your Help!

1 Like