2017-03-22 3 views
0

Ich habe diesen Media Player mit Unity 5.6 Video Player und RawImage-Komponente gemacht. Wenn ich es für + 40h gerade laufe, wird es nicht genügend Speicher haben und abstürzen. Fehlerprotokolle zeigen nur an, dass der Speicher niedrig ist.Unity 5.6: RAM-Auslastung wächst weiter

Gibt es etwas, was ich in meinem Code speichereffizienter machen könnte oder irgendwie den Speicherverbrauch reduzieren könnte?

Mein Test PC hat i3-Prozessor und 4GB RAM.

Vielen Dank für Ratschläge :)

Player.cs

using System.Collections; 
using System.Collections.Generic; 
using UnityEngine; 
using UnityEngine.UI; 
using System; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Net; 
using System.Text.RegularExpressions; 
using UnityEngine.Video; 

public class Play : MonoBehaviour 
{ 

    // Use this for initialization 

    bool develop = true; 
    bool web = false; 

    //UI & Audio 
    private VideoPlayer videoPlayer; 
    private VideoSource videoSource; 

    private AudioSource audioSource; 

    //Local 
    private string path = "file://"; 
    private string folder = "C:/medias/"; 
    private WaitForSeconds waitTime; 
    int arrLength; 
    int i = 0; 

    //Web (http) 
    private string webpath = "http://"; 
    string uri = "www.rtcmagazine.com/files/images/5353/"; 

    string source; 
    string str; 
    WWW www; 

    //Extensions to get 
    string[] extensions = new[] { ".jpg", ".JPG", ".jpeg", ".JPEG", ".png", ".PNG", ".mp4", ".MP4", ".webm", ".WEBM", ".avi", ".AVI" }; 

    FileInfo[] info; 
    DirectoryInfo dir; 

    void Start() 
    { 

     //Add VideoPlayer to the GameObject 
     videoPlayer = gameObject.AddComponent<VideoPlayer>(); 

     //Add AudioSource 
     audioSource = gameObject.AddComponent<AudioSource>(); 

     //Disable Play on Awake for both Video and Audio 
     videoPlayer.playOnAwake = true; 
     audioSource.playOnAwake = true; 

     if (web) { 
      string[] fetchFilesCount = GetFiles (webpath+uri); 
      int getLenght = fetchFilesCount.Length; 
      info = new FileInfo[getLenght]; 
      int counter = 0; 
      string[] filesFromWeb = GetFiles (webpath+uri); 
      foreach (String file in filesFromWeb) 
      { 
       info [counter] = new FileInfo(webpath+uri+file); 
       counter++; 

       if (counter == filesFromWeb.Length) { 
        counter = 0; 
       } 
      } 
     } else { 
      info = new FileInfo[]{}; 
      dir = new DirectoryInfo(@folder); 
      info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray(); 
     } 
     arrLength = info.Length; 

     Application.runInBackground = true; 
     StartCoroutine(looper()); 
    } 


    IEnumerator looper() 
    { 
     //Run forever 
     while (true) 
     { 
      if (i == arrLength - 1) 
      { 
       if (web) { 
        int counter = 0; 
        string[] filesFromWeb = GetFiles (webpath+uri); 
        foreach (String file in filesFromWeb) 
        { 
         info [counter] = new FileInfo(webpath+uri+file); 
         counter++; 

         if (counter == filesFromWeb.Length) { 
          counter = 0; 
         } 
        } 
       } else { 
        info = dir.GetFiles().Where (f => extensions.Contains (f.Extension.ToLower())).ToArray(); 
        arrLength = info.Length; 
       } 
       i = 0; 
      } 
      else 
      { 
       i++; 
      } 
      //Debug.Log(info[i]); 
      yield return StartCoroutine(medialogic()); 

      int dotIndex = info[i].ToString().LastIndexOf('.'); 

      //string lhs = index < 0 ? source : source.Substring(0,index), 
      string searchDot = dotIndex < 0 ? "" : source.Substring(dotIndex+1); 

      int dotPos = Array.IndexOf(extensions, "." + searchDot); 
      if (dotPos > 5) { 
       waitTime = new WaitForSeconds (0); 
      } else { 
       waitTime = new WaitForSeconds (7); 
      } 
      //Wait for 7 seconds 
      yield return waitTime; 
     } 
    } 

    IEnumerator medialogic() 
    { 
     source = info[i].ToString(); 

     if (web) { 
      if (develop) { 
       www = new WWW (source); 
      } else { 
       www = new WWW (webpath+uri+source); 
      } 
     } else { 
      if (develop) { 
       str = path + source; 
      } else { 
       str = path + folder + source; 
      } 
      www = new WWW (str); 
     } 

     int index = source.LastIndexOf('.'); 

     //string lhs = index < 0 ? source : source.Substring(0,index), 
     string rhs = index < 0 ? "" : source.Substring(index+1); 

     int pos = Array.IndexOf(extensions, "." + rhs); 
     if (pos > -1 && pos < 6) 
     { 
      //Wait for download to finish 
      yield return www; 
      GetComponent<RawImage>().texture = www.texture; 
     } 
     else if (pos > 5) 
     { 
      //videos here 
      videoPlayer.source = VideoSource.Url; 
      videoPlayer.url = str; 

      //Set Audio Output to AudioSource 
      videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource; 

      //Assign the Audio from Video to AudioSource to be played 
      videoPlayer.EnableAudioTrack(0, true); 
      videoPlayer.SetTargetAudioSource(0, audioSource); 

      //Set video To Play then prepare Audio to prevent Buffering 
      videoPlayer.Prepare(); 

      while (!videoPlayer.isPrepared) 
      { 
       yield return null; 
      } 

      //Assign the Texture from Video to RawImage to be displayed 
      GetComponent<RawImage>().texture = videoPlayer.texture; 

      //Play Video 
      videoPlayer.Play(); 

      //Play Sound 
      audioSource.Play(); 

      //Set loop to true, hack for a freeze bug 
      videoPlayer.isLooping = true; 

      //Alternative way to check if video has ended 
      videoPlayer.loopPointReached += EndReached; 

      //Debug.Log ("Play started"); 

      while (videoPlayer.isPlaying) 
      { 
       //Debug.Log ("playing"); 
       yield return null; 
      } 

      //Debug.Log("Done Playing Video"); 
     } 
    } 

    void EndReached(UnityEngine.Video.VideoPlayer videoPlayer) { 
     //Debug.Log("End reached!"); 
     //Play Video 
     videoPlayer.Stop(); 

     //Play Sound 
     audioSource.Stop(); 
    } 

    public static string[] GetFiles(string url) 
    { 
     string[] extensions2 = new[] { ".jpg", ".JPG", ".jpeg", ".JPEG", ".png", ".PNG", ".mp4", ".MP4", ".webm", ".WEBM", ".avi", ".AVI" }; 
     List<string> files = new List<string>(500); 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 
     using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
     { 
      using (StreamReader reader = new StreamReader(response.GetResponseStream())) 
      { 
       string html = reader.ReadToEnd(); 

       Regex regex = new Regex("<a href=\".*\">(?<name>.*)</a>"); 
       MatchCollection matches = regex.Matches(html); 

       if (matches.Count > 0) 
       { 
        foreach (Match match in matches) 
        { 
         if (match.Success) 
         { 
          string[] matchData = match.Groups[0].ToString().Split('\"'); 
          foreach (string x in extensions2) 
          { 
           if (match.ToString().Contains(x)) 
           { 
            files.Add(matchData[1]); 
           } 
          } 
          //files.Add(matchData[1]); 
         } 
        } 
       } 
      } 
     } 
     return files.ToArray(); 
    } 

    public static string[] getFtpFolderItems(string ftpURL) 
    { 
     FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpURL); 
     request.Method = WebRequestMethods.Ftp.ListDirectory; 

     //You could add Credentials, if needed 
     //request.Credentials = new NetworkCredential("anonymous", "password"); 

     FtpWebResponse response = (FtpWebResponse)request.GetResponse(); 

     Stream responseStream = response.GetResponseStream(); 
     StreamReader reader = new StreamReader(responseStream); 

     return reader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 
    } 
} 
+0

Haben Sie den ** Unity3D Profiler ** ausprobiert? https://docs.unity3d.com/Manual/ProfilerWindow.html – Smartis

+0

Wäre es schwer, diese Art von Ding zu erkennen, da die Ram-Nutzung mit der Zeit so wenig zunimmt? Ich meine, es hat ungefähr 30 Stunden gedauert, um 1 GB RAM mehr zu verbrauchen. –

+0

Überhaupt nicht. Überprüfen Sie das GC-Verhalten. Welche Objekte werden gelöscht und welche jedes Mal wieder instanziiert. – Smartis

Antwort

1

ist Ihr Code eindeutig zu lang und komplex toroughly zu analysieren und Sie sollten Ihre Anwendung Profil zu wissen, wo der größte Teil des Speichers geht, aber ich kann dir ein paar Hinweise geben.

Versuchen Sie, jede einzelne Zuweisung aus Ihrer Schleife zu entfernen. Ich bin mir nicht sicher, ob es eine Möglichkeit gibt, dieselben WWW oder WaitForSeconds Objekte wiederzuverwenden, aber Sie können versuchen, sie zu cachen und zu speichern, anstatt jedes Mal neue zu erstellen.

Auch foreach Schleifen zuweisen ein Enumerator Objekt. Sie können es in eine normale for Schleife konvertieren.

GetFiles ist selbst voll von Zuweisungen. Wenn sich Ihre URL nicht häufig ändert, können Sie das Ergebnis zwischenspeichern und wiederverwenden.

info = dir.GetFiles().Where (f => extensions.Contains (f.Extension.ToLower())).ToArray(); 

würde ich diese Linie studieren sehr eng: ToArray weist eine neue Array kopiert alle Elemente in der Enumerator. GetFiles wieder. Der Lambda-Ausdruck selbst benötigt eine Zuweisung. Sie können eine reguläre Methode erstellen und sie anstelle des Lambda-Ausdrucks verwenden. Ich bin nicht sicher über Where, aber ich denke, dass auch eine neue Liste zuweist. Möglicherweise möchten Sie alles entfernen.

Es gibt auch verschiedene String-Verkettungen in Ihrem Code und diese belegen auch Speicher. Verwenden Sie stattdessen eine StringBuilder.

Grundsätzlich ist Caching der Schlüssel, um Speicherzuweisungen im Allgemeinen zu reduzieren. Tun Sie es wo immer es möglich ist, wann immer es nötig ist.

+0

Sie sind falsch über 'foreach', [wenn Sie über ein Array foreach der Unity-Compiler verwandelt es in eine for-Anweisung während der Kompilierung, so dass es überhaupt keinen iterator erstellt] (https: // forum.unity3d.com/threads/foreach-massive-slower-than-for-when-looping-through-verizes.235011/#post-1560056). –

+0

Danke, das wusste ich nicht, aber er scheint foreach auch für eine MatchCollection zu verwenden und instanziiert ein neues Objekt. – dogiordano

Verwandte Themen