Is it good practice to keep calling `del` on objects that I don't need anymore?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
snake77
Posts: 31
Joined: Thu Jun 24, 2021 11:26 pm

Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by snake77 » Tue Jul 13, 2021 10:22 am

Is it good practice to keep calling

Code: Select all

del
on objects as soon as I don't need them anymore? (And not wait until it goes out of scope.)

Or does it not have an immediate effect anyway and would I have to call

Code: Select all

gc.collect()
every time, too? Or does it get called automatically if there would be not enough memory, to see if some memory can be freed up from a `del` call that happened in the meantime?

stijn
Posts: 735
Joined: Thu Apr 24, 2014 9:13 am

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by stijn » Wed Jul 14, 2021 6:20 am

del only removes the name from the scope so the object remeains as-is so indeed will not have immediate effect on memory until calling gc.collect(). Which indeed gets called automatically if there is not enough memory for an allocation. Whether it's good practice: depends. Littering your code with del/gc.collect() should imo really be a last resort because it makes things look unreadable and if it is needed it's a sign you're operating at the limit of what your platform can do and/or your code needs improving with respect to memory usage.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by pythoncoder » Wed Jul 14, 2021 8:50 am

I agree - I never use del. The GC algorithm detects objects which have gone out of scope and reclaims the RAM.

In large applications I run a task which periodically performs gc.collect(). This has three benefits. Firstly, I control when GC occurs so can opt to run it when it has least impact on application behaviour. Secondly, calling it regularly reduces the length of time taken by each invocation. Lastly, calling it regularly reduces RAM fragmentation.
Peter Hinch
Index to my micropython libraries.

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by jimmo » Wed Jul 14, 2021 12:11 pm

Echoing what pythoncoder and stjin said, you should only call "del" in very specific situations that are quite rare.

In general, if your approach is to break your code up into smaller functions and avoid re-assigning variables then you won't see the sort of problems where you might otherwise reach for "del".

(The point of the smaller functions is that everything goes out of scope at the end of the function and will therefore be immediately available for collection)

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by kevinkk525 » Wed Jul 14, 2021 9:16 pm

I only use "del" in long running loops which occasionally create large temporary data structures. (Afterwards I call gc.collect() to free that RAM). That way those variables don't take up unneccessary RAM.

Simple, yet weird example:

Code: Select all

while True: 
    a={}
    a.update(await get_results())
    await asyncio.sleep(10)
    a.update(await get_other_results())
    await publish(a)
    del a
    gc.collect()
    await do_something()
    await asyncio.sleep(10)
    await do_something()
    
Of course this could be avoided by using a function for all "a" related stuff.. I also use it when working with long temporary strings where creating new functions just doesn't work or makes no sense.

So all in all a very special use-case.
Generally "del" is hardly needed.


As for calling gc.collect(), this might look a bit strange but I came to realize that I prefer to call that function whenever I deal with larger data structures or importing modules.
On most devices or smaller projects it won't matter but with my big project on the esp8266 it has an enormous impact. Not calling gc.collect() or calling it at the wrong time makes the difference between having 3kB of continuous free space or not even being able to import all the modules because the RAM is already too fragmented (and that's with frozen modules).
Calling gc.collect() regularly until all modules are imported is an important part in keeping the RAM usable.
Later I call it only after larger data like after I'm done with a big string or dictionary, so that the next function doesn't have to deal with a heavily fragmented heap. (additionally to a regular gc.collect())
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by davef » Wed Jul 14, 2021 10:17 pm

Hi Kevin,
Calling gc.collect() regularly until all modules are imported is an important part in keeping the RAM usable.
I don't understand the "until all modules are imported" part.

I have gc.collect() sprinkled through the code without following what might be good practice. For example ... say I am running a while loop collecting data and once a day I call uMail to send the log. When would be the best times to call gc.collect()? Before calling a .py file that imports umail, before calling a function in umail or after sending the log has finished and I drop back to collecting data?

Thanks

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by kevinkk525 » Thu Jul 15, 2021 5:09 am

In my project I import multiple modules. After each import statement I call gc.collect() to free all the RAM that only was only temporarily used during import.
Then I call gc.collect() after creating bigger objects.
This ensures that the RAM is as continuously used as possible and the fragmentation as low as possible.

Code: Select all

import module1
gc.collect()
import module2
gc.collect()
import module3
gc.collect()

obj=module1.Class()
gc.collect()
say I am running a while loop collecting data and once a day I call uMail to send the log. When would be the best times to call gc.collect()? Before calling a .py file that imports umail, before calling a function in umail or after sending the log has finished and I drop back to collecting data?
I'd say after sending the mail you should call gc.collect() to free all temporary stuff. Also as mentioned above after each import. Before calling a function or importing modules is not needed, if collect was called after importing etc.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by davef » Thu Jul 15, 2021 6:56 am

Thank you for making the use of gc.collect() much clearer.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Is it good practice to keep calling `del` on objects that I don't need anymore?

Post by pythoncoder » Thu Jul 15, 2021 10:10 am

kevinkk525 wrote:
Thu Jul 15, 2021 5:09 am
...In my project I import multiple modules. After each import statement I call gc.collect()...
To expand on this, the point is that the statement

Code: Select all

import module
invokes the compiler which converts the Python source to bytecode in RAM. The compiler uses RAM and a subsequent run of GC reclaims this. If the next module requires a block of contiguous RAM, perhaps for a buffer, reclaiming RAM before doing the import reduces the risk of failure.
Peter Hinch
Index to my micropython libraries.

Post Reply