线程导致应用程序在iOS上滞后,但在Android上则不然



我正在Unity3D中为iOS和Android构建一个人脸检测应用程序。该应用程序应该每秒检测10张人脸。然而,每次人脸检测大约需要50毫秒,所以我决定让人脸检测在另一个线程的后台运行,以防止出现小的滞后峰值(应用程序需要每帧更新视觉内容,50毫秒的停止会使其滞后)。

问题是线程导致应用程序在iOS上滞后。在没有线程的情况下,它过去每秒检测10个面,现在有线程时检测2个。。它在安卓系统上运行良好。

奇怪的是,该应用程序在iOS上的前5秒运行良好。它是否检测到人脸并不重要,5秒后会出现严重的滞后。编辑:如果我暂停应用程序,然后继续它,滞后会像开始时一样再消失5秒。这是什么!?

下面是一个处理人脸检测的协同程序,它每秒运行10次。如果面部检测线程没有在100毫秒内完成,则会阻止另一个线程启动。

    IEnumerator FaceDetection()
    {
        while (true)
        {
            if (faceDetectionThreadDone)
            {
                rgbaMat = webCamTextureToMatHelper.GetMat();
                if (rgbaMat != null)
                {
                    OpenCVForUnityUtils.SetImage(faceLandmarkDetector, rgbaMat);
                    faceDetectionThreadDone = false;
                    new Thread(() =>
                    {
                        Thread.CurrentThread.IsBackground = true;
                        // heavy computing stuff (50 ms)
                        List<UnityEngine.Rect> detectResult = faceLandmarkDetector.Detect();
                        if (detectResult.Count > 0)
                        {
                            points = faceLandmarkDetector.DetectLandmark(detectResult[0]);
                        }
                        faceDetectionThreadDone = true;
                    }).Start();
                }
            }
            yield return new WaitForSeconds(0.1f);
        }
    }

我如何创建新线程是否存在严重问题?我在某个地方读到,一旦它们执行完毕,就会被垃圾收集器清理掉。这可能会造成滞后吗?构建设置设置在高性能等上

编辑:好的,我现在很确定这个问题与内存管理无关。我已经在Xcode中运行了内部探查器,并观察了堆的使用量。当垃圾收集器启动时,性能没有受到影响。

我测试该应用程序的设备:iPhone 6、索尼Z3、三星S4

创建和启动Thread非常昂贵。每次

Thread(() =>
{
//Code
}).Start();

被调用时,分配了大约1MB的内存。添加内部发生的其他内存分配,例如List(detectResult)创建。

另外,yield return new WaitForSeconds(0.1f);分配内存,但我认为这不是问题所在。您可以通过在while循环之前声明WaitForSeconds,然后使用它来防止这种情况。

例如,

//Create instance of WaitForSeconds once, before the while loop
WaitForSeconds waitForSeconds = new WaitForSeconds(0.1f);
while (true){
//your Thread code
}
yield return waitForSeconds; //No more memory allocation 

不要真的认为这是主要问题,但我想让你知道你可以这么做。对于我上面提到的Thread问题,您应该创建一个while循环,处理您的数据,然后在主Thread中执行输出。基本上是一个线程函数,它将永远循环,而不是每次创建一个新的Thread

有一个名为Unity Threading Helper的插件,它允许您从另一个线程调用Unity API函数。你可能想使用它。它有付费和免费版本。免费版本中没有包含示例。这是唯一的区别,但你可以在我发布的链接上下载它和示例。

下面是如何使用API的一般示例。阅读代码中的注释。你的工作是把问题中的代码放在合适的位置,这很容易做到

bool keepProcessing;
UnityThreading.ActionThread myThread;
void Start()
{
    keepProcessing = true;
    //Create Thread once
    myThread = UnityThreadHelper.CreateThread(() =>
    {
        //Will process Data forever!
        while (keepProcessing)
        {
            //Do heavy computing stuff 
            //Computing Done! Do something with the output data
             UnityThreadHelper.Dispatcher.Dispatch(() =>
              {
                   //You can safely call Unity API functions inside this codeblock
              }
            //Wait so that Unity won't Freeze
            Thread.Sleep(1);
        }
    });
}
void stopProcessing()
{
    keepProcessing = false;
    myThread.Abort();
}

最后,我建议您重新设计DetectLandmark函数,将array作为参数,而不是List。分配足够的数组内存一次,然后重复使用。这将完全删除应用程序中的内存分配。

在1/30帧中将Application.targetFrameRate设置为15,在29/30帧中将其设置为60解决了问题……

必须是Unity中与vsync相关的错误。。

相关内容

  • 没有找到相关文章

最新更新