Search Issue Tracker

Not Reproducible

Votes

0

Found in

2021.3.38f1

2022.3.28f1

6000.0.1f1

Issue ID

UUM-71455

Regression

No

VFX Graph Memory leak when calling the ClearPropertyBinders and AddRemoveVFXProperty

--

-

Reproduction steps:
1. Open the attached “Repro“ project
2. Open the “Assets/Scenes/TestScene.unity“ Scene
3. Open the Profiler window (Window > Analysis > Profiler)
4. Select the “Memory“ Profiler Module
5. Enter the Play Mode
6. Wait and observe the Native and Untracked Memory

Expected result: Native and Untracked Memory stays the same
Actual result: Native and Untracked Memory is slowly increasing

Reproducible with: 2021.3.38f1, 2022.3.28f1, 6000.0.1f1

Reproducible on: M1 MacOS 14.4.1
Not reproducible on: No other environment tested

  1. Resolution Note:

    I wasn't able to reproduce locally using 2022.3.29f1.
    However, I suspecting the memory growth only visible in windows task manager a result of many per frame allocation/destroy. You have to be aware AddPropertyBinder is actually allocating a new Monobehavior which isn't a small object.
    We are recommending usage of pooled object in this scenario and prevent creation of new property binder using "enable" property.

    For this specific use case, the VFXBind.cs file could be modified this way:
    ```
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Serialization;
    using UnityEngine.VFX;
    using UnityEngine.VFX.Utility;

    [ExecuteAlways]
    public class VFXBind : MonoBehaviour
    {
    [SerializeField]
    private VisualEffect vfx;
    [SerializeField]
    private VFXPropertyBinder vfxBinder;

    [SerializeField]
    private string propertyName;

    public VisualEffect VFX => vfx;

    private Transform target;

    static VFXPositionBinder GetFirstOrCreatePositionBinder(VFXPropertyBinder propertyBinder)
    {
    //Do *not* use GetPropertyBinders helper, it only iterate through active binders, GetComponent will return not enabled component
    var binder = propertyBinder.GetComponent<VFXPositionBinder>();
    if (binder == null)
    {
    binder = propertyBinder.AddPropertyBinder<VFXPositionBinder>();
    }

    return binder;
    }

    public void StartBind(Transform newTarget)
    {
    #if false
    vfxBinder.AddPropertyBinder(new VFXPositionBinder
    {
    Property = propertyName,
    Target = target
    });
    target = newTarget;
    vfx.enabled = false;
    Update();
    vfx.enabled = true;
    #endif
    vfx.enabled = false;
    //Suggestion: use Lazy allocation of VFXPositionBinder, keep it & reuse it
    //vfxBinder.ClearPropertyBinders();
    if (newTarget)
    {
    var binder = GetFirstOrCreatePositionBinder(vfxBinder);
    binder.Property = propertyName;
    binder.Target = newTarget;
    binder.enabled = true;
    }
    vfx.enabled = true;
    }

    public void StopBind()
    {
    //Suggestion: Don't clear it, only disable the binder
    //vfxBinder.ClearPropertyBinders();
    var binder = GetFirstOrCreatePositionBinder(vfxBinder);
    binder.enabled = false;
    }

    private void OnValidate()
    {
    vfx = GetComponent<VisualEffect>();
    vfxBinder = GetComponent<VFXPropertyBinder>();
    }

    private void Update()
    {
    if (target && vfx.HasVector3(propertyName))
    {
    //vfx.SetVector3(propertyName, target.position);
    }
    }

    #if UNITY_EDITOR
    [SerializeField]
    private Transform testTarget;

    [ContextMenu("Start Bind")]
    private void StartBindTest()
    {
    StartBind(testTarget);
    }

    [ContextMenu("End Bind")]
    private void EndBindTest()
    {
    StartBind(null);
    }
    #endif
    }
    ```
    => Since this object is instantiated in a pool, we can lazily allocate and enable/disable the required property binder. It prevents creating a new property binder every time an object is activated from the pool.

Add comment

Log in to post comment

All about bugs

View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.