Skip to content

Memory leak when iterating scenes; bproc.clean_up() becomes progressively slower #1194

@rb4005

Description

@rb4005

Describe the issue

Description:
I’m seeing a steadily increasing memory footprint when running BlenderProc in a loop to generate many scenes. Even though I call bproc.clean_up(True) (and force a Python gc.collect()), RAM usage, GPU memory and the time spent inside bproc.clean_up() grow with each iteration until the script ultimately crashes. I suspect that some internal data (Cycles render buffers) is never freed.

Expected Behavior:

  • Memory usage should remain roughly constant after each iteration (aside from small fluctuations).
  • bproc.clean_up(True) should consistently take a small, bounded amount of time (< 0.1 s).

Actual Behavior:

  • The RSS steadily increases by ~5–20 MB per iteration.
  • bproc.clean_up(True) time grows linearly until it dominates the iteration time.
  • The script eventually aborts due to out‐of‐memory or unacceptable slowdown.

Minimal code example

import blenderproc as bproc
import bpy
import os
import numpy as np
import random
import pandas as pd
import tqdm

# Nach dem Rendering
import gc
import time
import psutil

# import debugpy
# debugpy.listen(5678)
# debugpy.wait_for_client()

# Sammeln Sie alle Metriken in einer Liste
metrics_list = []

def log_performance_metrics(iteration, comment, output_dir):
    process = psutil.Process(os.getpid())
    mi = process.memory_info().rss / 1024 / 1024
    objs = len(bpy.data.objects)
    meshes = len(bpy.data.meshes)
    now = time.time()
    if hasattr(log_performance_metrics, "last"):
        it = now - log_performance_metrics.last
    else:
        it = 0.0
    log_performance_metrics.last = now

    metrics_list.append(
        {
            "comment": comment,
            "iteration": iteration,
            "memory_usage_mb": round(mi, 2),
            "blender_objects": objs,
            "blender_meshes": meshes,
            "timestamp": round(now, 2),
            "iteration_time": round(it, 2),
            "bpy.data.meshes": len(bpy.data.meshes),
            "bpy.data.objects": len(bpy.data.objects),
            "bpy.data.images": len(bpy.data.images),
            "bpy.data.materials": len(bpy.data.materials),
            "bpy.data.textures": len(bpy.data.textures),
            "Node Groups": len(bpy.data.node_groups),
        }
    )

    # Am Ende des Skripts (oder nach x Schleifen) einmal schreiben:
    df = pd.DataFrame(metrics_list)
    df.to_csv(
        os.path.join(output_dir, "performance_log.csv"),
        sep=";",
        decimal=",",  # Komma als Dezimaltrenner
        index=False,
    )
    return metrics_list[-1]

if __name__ == "__main__":
    output_dir_path = r"D:\output"
    os.makedirs(output_dir_path, exist_ok=True)
    n_scenes = 2000
    bproc.init()
    bproc.renderer.enable_depth_output(
        activate_antialiasing=False, output_dir=None, output_key="depth"
    )
    resolutions_render = [
        (1920, 1080),
        (1600, 1200),
        (1280, 960),
        (1280, 720),
        (1024, 1024),
        (640, 480),
    ]
    start_index = 0
    for iteration in tqdm.tqdm(range(n_scenes)):
        iter_start_time = time.time()
        start_metrics = log_performance_metrics(iteration, "0.)", output_dir_path)
        print(
            f"0.) Iteration {iteration}: Memory: {end_metrics['memory_usage_mb']:.2f} MB, Objects: {end_metrics['blender_objects']}, Time: {time.time() - iter_start_time:.2f}s"
        )
        resolution_render = random.choice(resolutions_render)
        bproc.clean_up(True)
        gc.collect()
        end_metrics = log_performance_metrics(iteration, "1.)", output_dir_path)
        
        print(
            f"1.) Iteration {iteration}: Memory: {end_metrics['memory_usage_mb']:.2f} MB, Objects: {end_metrics['blender_objects']}, Time: {time.time() - iter_start_time:.2f}s"
        )
        bproc.camera.set_resolution(resolution_render[0], resolution_render[1])
        bproc.utility.reset_keyframes()
        light = bproc.types.Light()
        light.set_location([0, 2, 4])
        light.set_energy(np.random.uniform(400, 500))
        poi = [0, 0, 0]
        location_cam = np.array([0, 0, 1])
        print("location_cam", location_cam)
        rotation_matrix = bproc.camera.rotation_from_forward_vec(
            poi - location_cam, inplane_rot=np.random.uniform(-0.7854, 0.7854)
        )
        cam2world_matrix = bproc.math.build_transformation_mat(
            location_cam, rotation_matrix
        )
        bproc.camera.add_camera_pose(cam2world_matrix)

        end_metrics = log_performance_metrics(iteration, "2.)", output_dir_path)
        print(
            f"2.) Iteration {iteration}: Memory: {end_metrics['memory_usage_mb']:.2f} MB, Objects: {end_metrics['blender_objects']}, Time: {time.time() - iter_start_time:.2f}s"
        )
        bproc.object.create_primitive("MONKEY", scale=[0.5, 0.5, 0.5])
        end_metrics = log_performance_metrics(iteration, "3.)", output_dir_path)
        print(
            f"3.) Iteration {iteration}: Memory: {end_metrics['memory_usage_mb']:.2f} MB, Objects: {end_metrics['blender_objects']}, Time: {time.time() - iter_start_time:.2f}s"
        )
        bproc.renderer.enable_segmentation_output(
            map_by="category_id", default_values={"category_id": 2}
        )
        bproc.renderer.set_output_format(enable_transparency=True)
        end_metrics = log_performance_metrics(iteration, "4.)", output_dir_path)
        print(
            f"4.) Iteration {iteration}: Memory: {end_metrics['memory_usage_mb']:.2f} MB, Objects: {end_metrics['blender_objects']}, Time: {time.time() - iter_start_time:.2f}s"
        )
        data = bproc.renderer.render()
        tree = bpy.context.scene.node_tree
        tree.nodes.remove(
            tree.nodes[-1]
        )  # ich muss das machen, weil enable_segmentation_output immer neue nodes erstellt.
        tree.nodes.remove(tree.nodes[-1])
        end_metrics = log_performance_metrics(iteration, "5.)", output_dir_path)
        print(
            f"5.) Iteration {iteration}: Memory: {end_metrics['memory_usage_mb']:.2f} MB, Objects: {end_metrics['blender_objects']}, Time: {time.time() - iter_start_time:.2f}s"
        )

Files required to run the code

No response

Expected behavior

  • Memory usage should remain roughly constant after each iteration (aside from small fluctuations).
  • bproc.clean_up(True) should consistently take a small, bounded amount of time (< 0.1 s).

BlenderProc version

BlenderProc 2.8.0

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions