Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory not freed when free_after_load is True #246

Open
jean-emmanuel opened this issue May 27, 2020 · 5 comments
Open

Memory not freed when free_after_load is True #246

jean-emmanuel opened this issue May 27, 2020 · 5 comments

Comments

@jean-emmanuel
Copy link
Contributor

jean-emmanuel commented May 27, 2020

Hi,
I'm having some trouble finding the source of this issue. I'm using pi3d on a linux desktop and I've been able to manage the video memory consumption well : the gpu memory is freed as expected when dereferencing the textures; however, I can't manage to free the RAM where the texture is stored as a numpy array, even when setting the free_after_load flag. Here is a minimal reproduction script, I'm monitoring the actual memory consumption with these two commands:

  •  free -h (ram)
  • glxinfo |grep "available.*memory" (vram)
import pi3d
import numpy
import time

textures = []
memory = 0
display = pi3d.Display.create(w=800, h=600)

# Warning ! adjust this to your card's capability
max_memory = 2048 * 1024 * 1024 # 2048MB


while display.loop_running():

    if memory < max_memory:

        tex = pi3d.Texture(numpy.full((1920,1080,4), dtype='uint8', fill_value=0), free_after_load=True, defer=False, mipmap=False)
        textures.append(tex)

        # tex.file_string points to tex.image -> should be deleted as well
        # (only relevant if texture object is kept somewhere ofc)
        tex.file_string = None

        memory += 1920 * 1080 * 4
        print('Loaded: %iMB' % int(memory / 1024 / 1024.))

    else:

        # uncommenting this frees the vram but not the ram
        # textures = []

        time.sleep(0.1)

Besides the tex.file_string reference I didn't find any living reference to the texture's array that would prevent garbage collection... any thoughts ?

@paddywwoof
Copy link
Collaborator

@jean-emmanuel I will have a look at this in an hour or two.. it does look odd, perhaps the highly optimised C and Fortran code in numpy skips some registration process, or the copying of the bytes is optimised into a transfer of ownership in some way?

@jean-emmanuel
Copy link
Contributor Author

jean-emmanuel commented May 27, 2020

Running the same test on a system with an integrated graphic card (and shared video memory) gave different results (same pi3d/numpy version):

  • the numpy array is allocated only once in python unless filled with a random value, I guess numpy detects the data is the same and reuses it. Somehow numpy behaves differently here... EDIT: creating the array with numpy.full instead of numpy.zero fixes it.
  • the memory is released as expected: half of it with free_after_load, the other half when textures are unloaded

@paddywwoof
Copy link
Collaborator

Yes it's very odd. Showing the memory with free doesn't seem to take into account GC released space in this circumstance. If I do something like

        if len(textures) > 50:
            textures.pop(0)

when it's building the list then the memory stops being consumed although new Texture objects are being created. Similarly if the else block sets textures to [] and memory to 0 then the process is repeated ad infinitum but the amount of memory consumed stays the the max. If I put the Texture.file_string = None into the Texture.free_after_load() method (where it should be, as you point out. Just in time for the next release of pi3d!) then the memory usage shown by free is higher but the first time textures is deleted it does drop. However subsequent resets don't reduce the memory usage. The memory usage does depend on what the numpy array is filled with (zero, ones, full, random) which is bizarre.

I might do some more experiments and get info from gc

@jean-emmanuel
Copy link
Contributor Author

jean-emmanuel commented May 28, 2020

Hmm, from what I understand memory management in opengl is hardware/driver dependent and nvidia driver may well keep memory allocated in ram as well as in vram (for swapping I guess). It may not be an issue with other hardwares (it isn't with that aforementioned intel integrated graphic card).

@jean-emmanuel
Copy link
Contributor Author

jean-emmanuel commented May 28, 2020

Running the script with a system ram consumption limit made it a lot slower but eventually all the textures got into the vram while ram usage stood under the limit (which was 4x lower than the total allocated vram), this could well corroborate the nvidia-swap theory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants