BGE leaves references in memory after quitting #44557

Closed
opened 2015-04-30 11:18:08 +02:00 by Sybren A. Stüvel · 24 comments

Description:

When the BGE quits, there are still remainders of game engine objects in memory. This can be seen when inspecting gc.get_objects(). These are probably dead proxies, which apparently can still hold references.

>>> import gc

 
### Before I run the game:
>>> o = [repr(o) for o in gc.get_objects()]

 
### fine, no error. Now I start the BGE, quit it, and do this again:
>>> o = [repr(o) for o in gc.get_objects()]

Traceback (most recent call last):
  File "/usr/lib/python3.4/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<blender_console>", line 1, in <module>
  File "<blender_console>", line 1, in <listcomp>

    SystemError: Blender Game Engine data has been freed, cannot use this python variable

Tested on: Blender 2.74 and latest version from Git (f8540d7fd5)
Running Kubuntu Linux 14.10 64-bit, compiled the version from Git with GCC 4.9.1-16ubuntu6

To reproduce:

  • Open bge-garbage-test.blend
  • Run the script and check the terminal for output. It should show a little header and then "Found nothing wrong."
  • Move the mouse into the 3D view and press P to start the GE.
  • Press ESC to stop the GE.

Run the script again, and check the terminal for output. On my machine it shows:

============================================================
Performing garbage check
============================================================
Found one: 7f0f6c3edc48 = Blender Game Engine data has been freed, cannot use this python variable
Referrers are:
    - 7f0f881044c8 = (dead proxy 'Blender Game Engine data has been freed, cannot use this python variable')
    - 7f0f6c3de408 = <module 'GameLogic'>
Referents are:
    - 7f0f6c176a08 = <built-in function getMaxLogicFrame>
    - 7f0f6cf19750 = (dead proxy 'Blender Game Engine data has been freed, cannot use this python variable')
    - 7f0f6c176ac8 = <built-in function setMaxPhysicsFrame>
    - 7f0f6c176c88 = <built-in function getExitKey>
    - 7f0f6c176348 = <built-in function expandPath>
    - 7f0f6c176848 = <built-in function addScene>
    - 7f0f6c176d88 = <built-in function getAverageFrameRate>
    - 7f0f6c176748 = <built-in function getCurrentController>
    - 7f0f6c176488 = <built-in function startGame>
    - 7f0fb8405ca0 = None
    - 7f0f6ededf60 = (dead proxy 'Blender Game Engine data has been freed, cannot use this python variable')
    - 7f0f6c3ed2c8 = [None, None, None, None, None, None, None, None]
    - 7f0f6c1765c8 = <built-in function saveGlobalDict>
    - 7f0f6c176dc8 = <built-in function getBlendFileList>
    - 7f0f6c1768c8 = <built-in function getRandomFloat>
    - 7f0f6c176a48 = <built-in function setMaxLogicFrame>
    - 7f0f6c3f0270 = 'GameLogic.error'
    - 7f0f6c176988 = <built-in function getSpectrum>
    - 7f0f6c176e88 = <built-in function PrintMemInfo>
    - 7f0f6c3eaac0 = 'This is the Python API for the game engine of bge.logic'
    - 7f0f6c1767c8 = <built-in function getSceneList>
    - 7f0f6c176508 = <built-in function endGame>
    - 7f0f6c176948 = <built-in function setGravity>
    - 7f0f6c176c48 = <built-in function setPhysicsTicRate>
    - 7f0f6c176b88 = <built-in function setLogicTicRate>
    - 7f0f6c1766c8 = <built-in function sendMessage>
    - 7f0f6c176e08 = <built-in function PrintGLInfo>
    - 7f0f6c176b08 = <built-in function getLogicTicRate>
    - 7f0f6c176f08 = <built-in function NextFrame>
    - 7f0f6c176f88 = <built-in function getProfileInfo>
    - 7f0f6c176d08 = <built-in function setExitKey>
    - 7f0fb8405ca0 = None
    - 7f0f6c176c08 = <built-in function getPhysicsTicRate>
    - 7f0f6c3ed7c8 = {}
    - 7f0f6c176788 = <built-in function getCurrentScene>
    - 7f0f6c3f0048 = <built-in function LibLoad>
    - 7f0f6c1762b0 = 'GameLogic'
    - 7f0f6c176548 = <built-in function restartGame>
    - 7f0f6c176648 = <built-in function loadGlobalDict>
    - 7f0f6c3f0108 = <built-in function LibList>
    - 7f0f6c3f0088 = <built-in function LibNew>
    - 7f0f6c3f00c8 = <built-in function LibFree>
    - 7f0fb8405ca0 = None
    - 7f0f6c176a88 = <built-in function getMaxPhysicsFrame>

I see two things amiss:

  • The GameLogic module still exists in memory. It's no longer contained in sys.modules though, I checked that.
  • Dead proxies can still hold references to other objects.
**Description:** When the BGE quits, there are still remainders of game engine objects in memory. This can be seen when inspecting `gc.get_objects()`. These are probably dead proxies, which apparently can still hold references. ``` >>> import gc ### Before I run the game: >>> o = [repr(o) for o in gc.get_objects()] ### fine, no error. Now I start the BGE, quit it, and do this again: >>> o = [repr(o) for o in gc.get_objects()] Traceback (most recent call last): File "/usr/lib/python3.4/code.py", line 90, in runcode exec(code, self.locals) File "<blender_console>", line 1, in <module> File "<blender_console>", line 1, in <listcomp> SystemError: Blender Game Engine data has been freed, cannot use this python variable ``` **Tested on:** Blender 2.74 and latest version from Git (f8540d7fd5a47bc9d1d676d5aaaa0de379c71637) Running Kubuntu Linux 14.10 64-bit, compiled the version from Git with GCC 4.9.1-16ubuntu6 **To reproduce:** - Open [bge-garbage-test.blend](https://archive.blender.org/developer/F168475/bge-garbage-test.blend) - Run the script and check the terminal for output. It should show a little header and then "Found nothing wrong." - Move the mouse into the 3D view and press P to start the GE. - Press ESC to stop the GE. # Run the script again, and check the terminal for output. On my machine it shows: ``` ============================================================ Performing garbage check ============================================================ Found one: 7f0f6c3edc48 = Blender Game Engine data has been freed, cannot use this python variable Referrers are: - 7f0f881044c8 = (dead proxy 'Blender Game Engine data has been freed, cannot use this python variable') - 7f0f6c3de408 = <module 'GameLogic'> Referents are: - 7f0f6c176a08 = <built-in function getMaxLogicFrame> - 7f0f6cf19750 = (dead proxy 'Blender Game Engine data has been freed, cannot use this python variable') - 7f0f6c176ac8 = <built-in function setMaxPhysicsFrame> - 7f0f6c176c88 = <built-in function getExitKey> - 7f0f6c176348 = <built-in function expandPath> - 7f0f6c176848 = <built-in function addScene> - 7f0f6c176d88 = <built-in function getAverageFrameRate> - 7f0f6c176748 = <built-in function getCurrentController> - 7f0f6c176488 = <built-in function startGame> - 7f0fb8405ca0 = None - 7f0f6ededf60 = (dead proxy 'Blender Game Engine data has been freed, cannot use this python variable') - 7f0f6c3ed2c8 = [None, None, None, None, None, None, None, None] - 7f0f6c1765c8 = <built-in function saveGlobalDict> - 7f0f6c176dc8 = <built-in function getBlendFileList> - 7f0f6c1768c8 = <built-in function getRandomFloat> - 7f0f6c176a48 = <built-in function setMaxLogicFrame> - 7f0f6c3f0270 = 'GameLogic.error' - 7f0f6c176988 = <built-in function getSpectrum> - 7f0f6c176e88 = <built-in function PrintMemInfo> - 7f0f6c3eaac0 = 'This is the Python API for the game engine of bge.logic' - 7f0f6c1767c8 = <built-in function getSceneList> - 7f0f6c176508 = <built-in function endGame> - 7f0f6c176948 = <built-in function setGravity> - 7f0f6c176c48 = <built-in function setPhysicsTicRate> - 7f0f6c176b88 = <built-in function setLogicTicRate> - 7f0f6c1766c8 = <built-in function sendMessage> - 7f0f6c176e08 = <built-in function PrintGLInfo> - 7f0f6c176b08 = <built-in function getLogicTicRate> - 7f0f6c176f08 = <built-in function NextFrame> - 7f0f6c176f88 = <built-in function getProfileInfo> - 7f0f6c176d08 = <built-in function setExitKey> - 7f0fb8405ca0 = None - 7f0f6c176c08 = <built-in function getPhysicsTicRate> - 7f0f6c3ed7c8 = {} - 7f0f6c176788 = <built-in function getCurrentScene> - 7f0f6c3f0048 = <built-in function LibLoad> - 7f0f6c1762b0 = 'GameLogic' - 7f0f6c176548 = <built-in function restartGame> - 7f0f6c176648 = <built-in function loadGlobalDict> - 7f0f6c3f0108 = <built-in function LibList> - 7f0f6c3f0088 = <built-in function LibNew> - 7f0f6c3f00c8 = <built-in function LibFree> - 7f0fb8405ca0 = None - 7f0f6c176a88 = <built-in function getMaxPhysicsFrame> ``` I see two things amiss: - The GameLogic module still exists in memory. It's no longer contained in `sys.modules` though, I checked that. - Dead proxies can still hold references to other objects.
Author
Member

Changed status to: 'Open'

Changed status to: 'Open'
Author
Member

Added subscribers: @dr.sybren, @brita

Added subscribers: @dr.sybren, @brita
Author
Member

PS: for fun, press F8 to reload scripts, then run the script again. Boom, Blender crashes (if not, try again).

PS: for fun, press F8 to reload scripts, then run the script again. Boom, Blender crashes (if not, try again).

Added subscriber: @AngusHollands-4

Added subscriber: @AngusHollands-4

We get into a heap of trouble (excuse the pun) because of persistent Python interpreter state, not only for internal objects, but also imported modules (any modules with mutable state that were imported before the engine was run will not be cleared after exit). This can be worked around, but it's a reflection of the issues observed.

We get into a heap of trouble (excuse the pun) because of persistent Python interpreter state, not only for internal objects, but also imported modules (any modules with mutable state that were imported before the engine was run will not be cleared after exit). This can be worked around, but it's a reflection of the issues observed.
Inês Almeida self-assigned this 2015-05-16 20:05:33 +02:00
Member

Added subscriber: @Blendify

Added subscriber: @Blendify

Added subscriber: @panzergame

Added subscriber: @panzergame

it seems that the GameLogic module is never freed, if you defined the destructor function you will see that is never called.

it seems that the GameLogic module is never freed, if you defined the destructor function you will see that is never called.

This issue was referenced by cd24871706

This issue was referenced by cd24871706411b2afd6e098e2b7c95c94bc2de38

Changed status from 'Open' to: 'Resolved'

Changed status from 'Open' to: 'Resolved'

This issue was referenced by 77ce7eb541

This issue was referenced by 77ce7eb5418e4f0adc5b5d9ac6d67a610f636b59
Author
Member

Changed status from 'Resolved' to: 'Open'

Changed status from 'Resolved' to: 'Open'
Author
Member

Commit cd24871706 re-introduced problems with starting the game engine multiple times in the same run of Blender. I have reverted in commit 77ce7eb541.

I've attached a project that shows this issue: #44557-memleak-reloading.tar.bz2. Run the BGE once, and it'll stop immediately (correctly, due to the bge.logic.endGame() call in t44557.bge.submodule2.startup). Run the BGE again, and you'll see a nice error message.

It probably has something to do with the t44557.bge module already getting loaded from Blender, before the BGE starts. However, I feel that we should still support this (and apart from the memory leak, it works fine in current Blender).

Commit cd24871706 re-introduced problems with starting the game engine multiple times in the same run of Blender. I have reverted in commit 77ce7eb5418e4f. I've attached a project that shows this issue: [#44557-memleak-reloading.tar.bz2](https://archive.blender.org/developer/F228110/T44557-memleak-reloading.tar.bz2). Run the BGE once, and it'll stop immediately (correctly, due to the `bge.logic.endGame()` call in `t44557.bge.submodule2.startup`). Run the BGE again, and you'll see a nice error message. It probably has something to do with the `t44557.bge` module already getting loaded from Blender, before the BGE starts. However, I feel that we should still support this (and apart from the memory leak, it works fine in current Blender).

Added subscriber: @you.le

Added subscriber: @you.le

Hi, I can't reproduce this bug with recent Blender's version... Or I'm missing something? http://www.pasteall.org/pic/95569

Hi, I can't reproduce this bug with recent Blender's version... Or I'm missing something? http://www.pasteall.org/pic/95569

@dr.sybren, as i understand the GameLogic module is never freed and reused the next frame because it contains only "globalDict" which is set as game end if we just reload an other file.

An other simple test is to do:

    if not hasattr(bge.logic, "a"):
        bge.logic.a = 0
    bge.logic.a = bge.logic.a + 1
    print(dir(bge.logic), bge.logic.a)

And then you will see that "a" is incremented for each run. But i debug the code in some hours and didn't find why it reuse the same module dictionnary because the module pointer and dictionnary is always a new modules, also the system modules dict is the same.
And even if we free the module by doing :

while (gameLogic->ob_refcnt) {
    PyDECREF(gameLogic);
}

The issue is still here.

Trying to import "bge" or "bge.logic" or "GameLogic" outside bge raise an eror as exepted.

@dr.sybren, as i understand the GameLogic module is never freed and reused the next frame because it contains only "globalDict" which is set as game end if we just reload an other file. An other simple test is to do: ``` if not hasattr(bge.logic, "a"): bge.logic.a = 0 bge.logic.a = bge.logic.a + 1 print(dir(bge.logic), bge.logic.a) ``` And then you will see that "a" is incremented for each run. But i debug the code in some hours and didn't find why it reuse the same module dictionnary because the module pointer and dictionnary is always a new modules, also the system modules dict is the same. And even if we free the module by doing : ``` while (gameLogic->ob_refcnt) { PyDECREF(gameLogic); } ``` The issue is still here. Trying to import "bge" or "bge.logic" or "GameLogic" outside bge raise an eror as exepted.

Also a big point that i forget : i renamed the folder bge to bge2

Also a big point that i forget : i renamed the folder bge to bge2

Apparently clear the sys.modules dictionnary before run the BGE and after run your script make it works. But it means that the BGE can't work on a python "context" modified by blender. So i propose to do like BGE : at blender start make a copy of the sys.modules and when laucnh the BGE load this copied dictionnary.

Apparently clear the sys.modules dictionnary before run the BGE and after run your script make it works. But it means that the BGE can't work on a python "context" modified by blender. So i propose to do like BGE : at blender start make a copy of the sys.modules and when laucnh the BGE load this copied dictionnary.
little fix patch : http://www.pasteall.org/67417/diff
Member

Removed subscriber: @Blendify

Removed subscriber: @Blendify

We need to be sure that after exiting the game, the original sys.modules entries are returned (your patch would leave the python modules dictionary in the same state as a clean blender instance (not preserving running addons etc)

We need to be sure that after exiting the game, the original sys.modules entries are returned (your patch would leave the python modules dictionary in the same state as a clean blender instance (not preserving running addons etc)

@AngusHollands-4: in the patch we first copy the actual sys.modules then set the clean one and at the game end we restore the copy of the actual sys.modules. So everything is ok.

@AngusHollands-4: in the patch we first copy the actual sys.modules then set the clean one and at the game end we restore the copy of the actual sys.modules. So everything is ok.
Member

Changed status from 'Open' to: 'Archived'

Changed status from 'Open' to: 'Archived'
Member

This task is being closed because the BGE has been removed in Blender 2.8.

This task is being closed because the BGE has been removed in Blender 2.8.
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
6 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#44557
No description provided.