Page MenuHome

Memory leak if both a shader and an AddonPreferences class are used
Confirmed, LowPublicBUG


System Information
Operating system: Windows-10-10.0.18362 64 Bits
Graphics card: GeForce RTX 2080/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 431.86

Blender Version
Broken: version: Official 2.80 (sub 75), branch: master, commit date: 2019-07-29 14:47, hash: rBf6cb5f54494e

Short description of error
Blender shows the warning Error: Not freed memory blocks: 4, total unfreed memory 0.012421 MB when an addon uses both AddonPreferences with an implementation of the draw() method and an instance of gpu.types.GPUShader.

Exact steps for others to reproduce the error

  • Install the following demo addon:
  • Start Blender from console with blender.exe --factory-startup --addons memleak
  • Exit Blender. It will print Error: Not freed memory blocks: 4, total unfreed memory 0.012421 MB.

If you open the addon in a text editor and comment out line 30 (shader = gpu.types.GPUShader(vertex_shader, fragment_shader)), the error is no longer shown.
Similarly, if you comment out lines 37 and 38 instead (def draw(self, context): pass) and leave line 30 enabled, the error will also not show up.
Of course this problem might also be caused by other conditions, but those two (shader and AddonPreferences class) are the combination where I spotted the problem first.

Related Objects

Event Timeline

Germano Cavalcante (mano-wii) lowered the priority of this task from 90 to Low.EditedNov 6 2019, 3:00 PM

Although it is not recommended to create and keep a reference to an object type Shader in the top level of a module (shaders are slow to create and use a lot of GPU resources),
the fact that an object of type AddonPreferences results in a memory leak indicates that somewhere in the creation of such object has a wrong refcount.

This is something that deserves investigation but doesn't have much priority.

it is not recommended to create and maintain a reference to an object type shader in the top level of a module (shaders are slow to create and use a lot of GPU resources)

Why would that be a problem? This code is executed exactly once at Blender startup.
(This is a bit off-topic, but I would appreciate to learn more about this comment)

Sybren A. Stüvel (sybren) changed the subtype of this task from "Report" to "Bug".Jan 23 2020, 12:57 PM

Python doesn't always free everything cleanly when the program quits. The memory leak could be due to having any registerable classes in the module, which could impact the order in which things are freed.
I tested the above, and the problem doesn't occur when replacing the bpy.types.AddonPreferences superclass with a bpy.types.Panel or bpy.types.Operator.

This code is executed exactly once at Blender startup.

It's also re-executed when reloading scripts.

I would recommend allocating things in the register() function instead, and freeing in unregister(). This is what I do in the Blender Cloud add-on, for example: This doesn't resolve this issue, but at least you only create the shader when the add-on is enabled.

The register/unregister does not fix the issue

1bl_info = {
2 "name": "shader mem leak demo",
3 "author": "Simon Wendsche (B.Y.O.B.)",
4 "category": "",
5 "blender": (2, 80, 0),
8vertex_shader = '''
9 void main()
10 {
11 gl_Position = vec4(0, 0, 0, 0);
12 }
15fragment_shader = '''
16 void main()
17 {
18 gl_FragColor = vec4(0, 0, 0, 0);
19 }
22import gpu
23from os.path import basename, dirname
24from bpy.utils import register_class, unregister_class
25from bpy.types import AddonPreferences
27addon_name = basename(dirname(__file__))
29# If this line commented out, the leak does not appear
31shader = None
33class TestAddonPreferences(AddonPreferences):
34 bl_idname = addon_name
36 # If this function is commented out, the leak does not appear
37 def draw(self, context):
38 pass
41def register():
42 global shader
43 shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
44 register_class(TestAddonPreferences)
46def unregister():
47 global shader
48 unregister_class(TestAddonPreferences)
49 del shader

Interesting that commenting out the draw method fixes the issue or using a different base class. I also tried some variations with class variables.