PhotoCaputure 导致 Unity 中的内存泄漏

Posted

技术标签:

【中文标题】PhotoCaputure 导致 Unity 中的内存泄漏【英文标题】:PhotoCaputure causes memory leak in Unity 【发布时间】:2021-11-12 01:33:28 【问题描述】:

我正在使用 unity 的 Photocapture Object 拍摄带有 hololens 的视频。 我根据官方的示例代码写了代码,但是我在更新函数中改变了过程,以获取多张图片而不是一张。

https://docs.unity3d.com/2018.4/Documentation/Manual/windowsholographic-photocapture.html

但是,当我运行此代码时,它最终会用完 pagefile.sys、内存不足并中止。 我搜索并发现大多数内存泄漏是由纹理 2d 引起的,但是在这段代码中,即使我省略了它们,它们也会发生。此外,在执行代码后,统一分析器不会显示内存使用量的任何逐渐增加。 可能是什么原因?如果您能告诉我,我将不胜感激。

using UnityEngine;
using System;
using System.Linq;
using UnityEngine.XR;
using UnityEngine.Windows.WebCam;
using System.Threading.Tasks;
using UnityEngine.Networking;
using System.Text;
using System.IO;
using System.Net;
using System.Collections;
using System.Collections.Generic;

public class photocap : MonoBehaviour

    PhotoCapture PhotoCapture = null;
    Texture2D targetTexture = null;
    Resolution cameraResolution;
    Renderer quadRenderer;
    float dt = 0;



    void Start()
    
        cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
        GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
        quad.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
        quadRenderer = quad.GetComponent<Renderer>() as Renderer;
        quadRenderer.material = new Material(Shader.Find("Unlit/Texture"));


        quad.transform.parent = this.transform;
        quad.transform.localPosition = new Vector3(0.0f, 0.0f, 0.3f);

    


    async void StartCapture()
    


        PhotoCapture.CreateAsync(false, delegate (PhotoCapture captureObject)
        
            PhotoCapture = captureObject;
            CameraParameters cameraParameters = new CameraParameters();
            cameraParameters.hologramOpacity = 0.0f;
            cameraParameters.cameraResolutionWidth = cameraResolution.width;
            cameraParameters.cameraResolutionHeight = cameraResolution.height;
            cameraParameters.pixelFormat = CapturePixelFormat.BGRA32;


            PhotoCapture.StartPhotoModeAsync(cameraParameters, delegate (PhotoCapture.PhotoCaptureResult result)
            

                PhotoCapture.TakePhotoAsync(OnCapturedPhotoToMemory);
            );
        );
    

    void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
    



        PhotoCapture.StopPhotoModeAsync(OnStoppedPhotoMode);


    

    void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
    

        PhotoCapture.Dispose();
        PhotoCapture = null;
    
    void Update()
    
        dt += Time.deltaTime;

        if (dt > 3)
        
            dt = 0.0f;
            StartCapture();
        

    




【问题讨论】:

【参考方案1】:

我很确定您也希望/必须处理 photoCaptureFrame

否则存储的纹理将永远留在您的应用程序内存中。

void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)

    // TODO: Obviously you first would want to do something with the just captured image ...

    photoCaptureFrame.Dispose();

    PhotoCapture.StopPhotoModeAsync(OnStoppedPhotoMode);


还有一件事:

您当前正在根据过去的时间开始新的捕获。

如果拍照、处理数据和处理的时间超过该间隔会怎样?

您可能更希望仅在第一次捕获实际完全完成后才触发新的捕获延迟!

实际上,为什么还要一直创建、启动、停止和处理捕获?您可以坚持使用一个并始终重复使用它

private PhotoCapture _photoCapture = null;
private Texture2D targetTexture = null;
private Resolution cameraResolution;
private Renderer quadRenderer;
private float dt = 0;

private void Start()

    cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
    var quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
    quad.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
    quadRenderer = quad.GetComponent<Renderer>();
    quadRenderer.material = new Material(Shader.Find("Unlit/Texture"));

    targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);

    quadRenderer.material.mainTexture = targetTexture;

    quad.transform.parent = transform;
    quad.transform.localPosition = new Vector3(0.0f, 0.0f, 0.3f);

    StartCapture();


private void StartCapture()

    PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);


private void OnPhotoCaptureCreated(PhotoCapture captureObject)

    _photoCapture = captureObject;
    var cameraParameters = new CameraParameters
    
        hologramOpacity = 0.0f,
        cameraResolutionWidth = cameraResolution.width,
        cameraResolutionHeight = cameraResolution.height,
        pixelFormat = CapturePixelFormat.BGRA32
    ;

    _photoCapture.StartPhotoModeAsync(cameraParameters, OnPhotoCaptureStarted);


private void OnPhotoCaptureStarted(PhotoCapture.PhotoCaptureResult result)

    // Take the first picture
    TakePhoto();
    // or if you really want more delay
    //Invoke(nameof(TakePhoto, 3f));


private void TakePhoto()

    _photoCapture.TakePhotoAsync(OnCapturedPhotoToMemory);


private void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)

    // Don't all the time destroy and create textures
    // simply upload the new data to the already existing image
    photoCaptureFrame.UploadImageDataToTexture(targetTexture);

    Debug.Log("Captured");

    photoCaptureFrame.Dispose();

    // without the overhead of stopping and disposing etc simply take the next image
    TakePhoto();
    // or if you really want more delay
    //Invoke(nameof(TakePhoto, 3f));

【讨论】:

谢谢,我尝试添加 photoCaptureFrame.Dispose();但它仍然会泄漏内存。 @lain 这是你的全部代码吗?你到底在用捕获的图像做什么?因为目前您的代码根本没有显示...您只是将帧捕获到内存...但是为了什么? @lain 你也说the unity profiler does not show any gradual increase in memory usage after the code is executed ...那你怎么知道有内存泄漏?我无法使用答案底部的代码重现这一点......我只删除了在前一个完成之前尝试开始的照片捕获引起的错误 省略了其余代码以澄清问题。我的整个代码在以下链接上。我计划将照片发送到服务器进行 AI 处理,但我目前处于可视化阶段。 github.com/pacifinapacific/MR_sample/blob/main/PhotocapW.cs 为什么总是破坏和创造一个新的纹理?只需创建一次并使用 photoCaptureFrame.UploadImageDataToTexture(targetTexture); 将其更新为相同的纹理

以上是关于PhotoCaputure 导致 Unity 中的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

Unity 中的简单套接字服务器

Unity3D使用指定动态字体,导致打包的时候包的体积增大的解决办法

Unity中的Update与FixedUpdate

Unity中的Update与FixedUpdate

unity中人物为什么会自己动

10.Unity2018中的地形——Terrain(一)