Python/BMesh: Add/removing textures between renders causes memory leak/ram crash #55954

Open
opened 2018-07-12 21:06:54 +02:00 by Charles West · 14 comments

System Information
Operating system and graphics card
Ubuntu 18.04, Nvidia GTX 960M

Blender Version
Broken: blender-2.80-17bc0567268-linux-glibc219-x86_64

Working Blender Version
Blender 2.79b stable (ubuntu repository) with cycles

Short description of error
If you run the attached code and target it a directory with a large number of images, it will repeatedly:

  1. Load an image from file
  2. Set the image to be the content of a "Image Texture" node
  3. Delete/remove the image that use to be the image texture node
  4. Render

As it processes images, blender takes more and more memory. Eventually it will crash. If you leave out step 4, then it will not.

Exact steps for others to reproduce the error
Based on a (as simple as possible) attached .blend file with minimum amount of steps

Import python code, run

LoadAndRemoveTextures("/folderWithManyImages", 2000)

in the console window.

imageMemoryProblem-WorksWithStableCycles.blend
imageMemoryProblem2pt80.blend

Code:

import datetime
import sys

import bpy
import bmesh
from mathutils import Vector
from mathutils import Euler
from bpy_extras.object_utils import world_to_camera_view
import random
import math
import json

import time
import os
import gc

def RemoveImageFromMemory (passedName):
    # Extra test because this can crash Blender.
    img = bpy.data.images[passedName]
    try:
        img.user_clear()
        can_continue = True
    except:
        can_continue = False
    
    if can_continue == True:
        try:
            bpy.data.images.remove(img, True)
            result = True
        except:
            result = False
    else:
        result = False
    return result

def CollectBackgroundImagePaths(sourceDirectoryPath, imageExtension):
    file_paths = []

    for root, dirs, files in os.walk(sourceDirectoryPath):
        for file_name in files:
            if file_name.endswith(imageExtension):
                file_paths.append(root + "/" + file_name)
    return file_paths

def SetBackgroundImage(backgroundImagePath):
    #Store reference to old image so it can be removed
    old_image_name = bpy.data.materials[0].node_tree.nodes.get("Image Texture").image.name

    #Load new image to be used
    new_image = bpy.data.images.load(filepath = backgroundImagePath)

    #Set the new image to be used
    bpy.data.materials[0].node_tree.nodes.get("Image Texture").image = new_image

    #Delete the old one from the file
    remove_succeeded = RemoveImageFromMemory(old_image_name)
    gc.collect()

    if not remove_succeeded:
        print("Error removing " + old_image_name)
    else:
        print("Removing " + old_image_name + " worked")

def LoadAndRemoveTextures(texturesFolderPath, numberToLoad):
    background_image_paths = CollectBackgroundImagePaths(texturesFolderPath, ".png")

    for example_index in range(0, numberToLoad):
        SetBackgroundImage(random.choice(background_image_paths))

        #If you alternate adding/removing images and rendering, it will eat all the ram on your system and crash
        bpy.ops.render.render( write_still=True )
**System Information** Operating system and graphics card Ubuntu 18.04, Nvidia GTX 960M **Blender Version** Broken: blender-2.80-17bc0567268-linux-glibc219-x86_64 **Working Blender Version** Blender 2.79b stable (ubuntu repository) with cycles **Short description of error** If you run the attached code and target it a directory with a large number of images, it will repeatedly: 1. Load an image from file 2. Set the image to be the content of a "Image Texture" node 3. Delete/remove the image that use to be the image texture node 4. Render As it processes images, blender takes more and more memory. Eventually it will crash. If you leave out step 4, then it will not. **Exact steps for others to reproduce the error** Based on a (as simple as possible) attached .blend file with minimum amount of steps Import python code, run LoadAndRemoveTextures("/folderWithManyImages", 2000) in the console window. [imageMemoryProblem-WorksWithStableCycles.blend](https://archive.blender.org/developer/F3919607/imageMemoryProblem-WorksWithStableCycles.blend) [imageMemoryProblem2pt80.blend](https://archive.blender.org/developer/F3919613/imageMemoryProblem2pt80.blend) Code: ``` import datetime import sys import bpy import bmesh from mathutils import Vector from mathutils import Euler from bpy_extras.object_utils import world_to_camera_view import random import math import json import time import os import gc def RemoveImageFromMemory (passedName): # Extra test because this can crash Blender. img = bpy.data.images[passedName] try: img.user_clear() can_continue = True except: can_continue = False if can_continue == True: try: bpy.data.images.remove(img, True) result = True except: result = False else: result = False return result def CollectBackgroundImagePaths(sourceDirectoryPath, imageExtension): file_paths = [] for root, dirs, files in os.walk(sourceDirectoryPath): for file_name in files: if file_name.endswith(imageExtension): file_paths.append(root + "/" + file_name) return file_paths def SetBackgroundImage(backgroundImagePath): #Store reference to old image so it can be removed old_image_name = bpy.data.materials[0].node_tree.nodes.get("Image Texture").image.name #Load new image to be used new_image = bpy.data.images.load(filepath = backgroundImagePath) #Set the new image to be used bpy.data.materials[0].node_tree.nodes.get("Image Texture").image = new_image #Delete the old one from the file remove_succeeded = RemoveImageFromMemory(old_image_name) gc.collect() if not remove_succeeded: print("Error removing " + old_image_name) else: print("Removing " + old_image_name + " worked") def LoadAndRemoveTextures(texturesFolderPath, numberToLoad): background_image_paths = CollectBackgroundImagePaths(texturesFolderPath, ".png") for example_index in range(0, numberToLoad): SetBackgroundImage(random.choice(background_image_paths)) #If you alternate adding/removing images and rendering, it will eat all the ram on your system and crash bpy.ops.render.render( write_still=True ) ```
Author

Added subscriber: @charlesrwest

Added subscriber: @charlesrwest
Author

Further investigation reveals that switching the renderer from Eevee to cycles also makes it stop eating all the ram, so it seems to be Eevee specific.

Further investigation reveals that switching the renderer from Eevee to cycles also makes it stop eating all the ram, so it seems to be Eevee specific.

Added subscriber: @mont29

Added subscriber: @mont29

Hrmmpfs… this is crashing here, in the scene_update call from render operator… depsgraph tries to access freed image ID, which is weird since relations are tagged to be updated in ID relink code.

No time to investigate further, but there are definitively issues here!

Hrmmpfs… this is crashing here, in the scene_update call from render operator… depsgraph tries to access freed image ID, which is weird since relations are tagged to be updated in ID relink code. No time to investigate further, but there are definitively issues here!
Author

If I may ask, is there anything I can do to bump up priority on this? I'm doing some deep learning research that requires 3 million+ examples to be generated and switching from Eevee to Cycles with low samples has made rendering time go from 2.5 days to something like 10 days while reducing quality.

Can I post a bounty or something?

If I may ask, is there anything I can do to bump up priority on this? I'm doing some deep learning research that requires 3 million+ examples to be generated and switching from Eevee to Cycles with low samples has made rendering time go from 2.5 days to something like 10 days while reducing quality. Can I post a bounty or something?

Added subscriber: @zakleap

Added subscriber: @zakleap

Removed subscriber: @zakleap

Removed subscriber: @zakleap

Added subscriber: @zakleap

Added subscriber: @zakleap

I have found that this causes the Syncing memory to keep going up unbounded. On first render, memory peak is around 4000Mb, on the second it goes up to 8000Mb. This has completely killed my ability to render my scene.

I have found that this causes the `Syncing` memory to keep going up unbounded. On first render, memory peak is around 4000Mb, on the second it goes up to 8000Mb. This has completely killed my ability to render my scene.
Philipp Oeser changed title from Add/removing textures between renders causes memory leak/ram crash to Python/BMesh: Add/removing textures between renders causes memory leak/ram crash 2019-11-05 12:32:50 +01:00

Added subscriber: @gizatt

Added subscriber: @gizatt

Removed subscriber: @gizatt

Removed subscriber: @gizatt

Added subscriber: @gizatt

Added subscriber: @gizatt

Added subscriber: @iss

Added subscriber: @iss

Same "leak" happens with cycles as soon as I unpack list of loaded images in image editor (slowly and progressively - loading thumbnails?)
When I reload blend file images are gone, so they didn't have users.

Same "leak" happens with cycles as soon as I unpack list of loaded images in image editor (slowly and progressively - loading thumbnails?) When I reload blend file images are gone, so they didn't have users.
Philipp Oeser removed the
Interest
Python API
label 2023-02-10 09:04:47 +01:00
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
5 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#55954
No description provided.