Skip to content

System Used Memory increases when recording repeatedly with RealtimeInstantReplaySession #97

@ynakano-hky

Description

@ynakano-hky

アプリ画面の内容を動画として保存する際に使用させて頂いています。 RealtimeInstantReplaySession を使用して画面やRenderTextureの内容を繰り返し動画として出力すると、アプリのメモリ使用量がどんどん上がっていく現象に遭遇しています。

環境は windows11 25H2、
scripting backend は mono、
Unityのバージョンは 6000.0.65f1 です。

使用バージョンはおそらく d194c16 です。
(おそらく、というのは2/25の夕方にmainのzipをDLしたものを使ったため明確なバージョンが特定できてないです。)

検証用プロジェクトの画面収録

5分かけて30秒の動画を繰り返し出力していますがメモリ使用量が増加していく様子を記録しました。

InstantReplayProj.2026-02-26.13-14-07.webm

特に8本目の動画を保存した後、次の収録開始時にメモリ使用量が顕著に跳ね上がります (4:10 あたり)

検証に使ったソースコード
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using InstantReplay;
using Unity.Profiling;
using UnityEngine;
using UnityEngine.UI;

public class SampleScene : MonoBehaviour
{
    [SerializeField] private Text _timeText;
    [SerializeField] private float _recordSeconds = 30f;
    [SerializeField] private float _waitSeconds = 1f;
    [SerializeField] private string _outputDirectoryName = "InstantReplayVideos";

    private int _recCounter;
    private string _status = "Idle";
    private string _lastOutputPath = "-";
    private CancellationTokenSource _loopCancellation;
    private ProfilerRecorder _systemUsedMemoryRecorder;

    private void OnEnable()
    {
        _systemUsedMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "System Used Memory");
        _loopCancellation = new CancellationTokenSource();
        _ = RecordLoopAsync(_loopCancellation.Token);
    }

    private void OnDisable()
    {
        if (_loopCancellation != null)
        {
            _loopCancellation.Cancel();
            _loopCancellation.Dispose();
            _loopCancellation = null;
        }

        if (_systemUsedMemoryRecorder.Valid)
            _systemUsedMemoryRecorder.Dispose();
    }

    private void Update()
    {
        if (_timeText == null)
            return;

        var systemUsedMemoryMb = GetSystemUsedMemoryMb();
        _timeText.text =
            $"{DateTimeOffset.Now:HH:mm:ss}\ncount={_recCounter} status={_status}\nlast={_lastOutputPath}\nmem={systemUsedMemoryMb:0.0}MB";
    }

    private async Task RecordLoopAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            RealtimeInstantReplaySession session = null;
            try
            {
                _status = "Recording";
                session = RealtimeInstantReplaySession.CreateDefault();

                await Task.Delay(TimeSpan.FromSeconds(_recordSeconds), cancellationToken);

                _status = "Exporting";
                var outputPath = BuildOutputPath(_recCounter + 1);
                var savedPath = await session.StopAndExportAsync(_recordSeconds, outputPath);

                _recCounter++;
                _lastOutputPath = Path.GetFileName(savedPath);
                _status = "Saved";
                Debug.Log($"InstantReplay saved: {savedPath}");
            }
            catch (OperationCanceledException)
            {
                break;
            }
            catch (Exception ex)
            {
                _status = "Error";
                Debug.LogException(ex);
            }
            finally
            {
                session?.Dispose();
            }

            // cleanup
            Resources.UnloadUnusedAssets();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            try
            {
                _status = "Waiting";
                await Task.Delay(TimeSpan.FromSeconds(_waitSeconds), cancellationToken);
            }
            catch (OperationCanceledException)
            {
                break;
            }
        }

        _status = "Stopped";
    }

    private string BuildOutputPath(int sequence)
    {
        var directory = Path.Combine(Application.persistentDataPath, _outputDirectoryName);
        Directory.CreateDirectory(directory);
        var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
        return Path.Combine(directory, $"InstantReplay_{timestamp}_{sequence:D4}.mp4");
    }

    private double GetSystemUsedMemoryMb()
    {
        if (!_systemUsedMemoryRecorder.Valid || _systemUsedMemoryRecorder.Count == 0)
            return 0d;

        return _systemUsedMemoryRecorder.LastValue / (1024d * 1024d);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions