Search Unity

Hololens UDP Client with DatagramSocket and Memory leak

Discussion in 'VR' started by Gabrio, Nov 15, 2018.

  1. Gabrio

    Gabrio

    Joined:
    Jan 31, 2016
    Posts:
    17
    Hi,
    I'm doing a simple UDPClient for Hololens to show messages sent from a UDP Server.
    I'm using DatagramSocket as found on MSDN example and some Forums.
    The problem is that when I start reading from the socket, the memory increase and I'm not able to free it.
    Stopping the reading the memory remain constant and never decrease. Also using GC.Collect every 2 seconds.
    This is the code I'm using

    Code (CSharp):
    1. using System.Text;
    2. using TMPro;
    3. using UnityEngine;
    4. using System;
    5. using System.Net;
    6. #if UNITY_EDITOR
    7. using System.Net.Sockets;
    8. using System.Threading;
    9. #else
    10. using Windows.Networking.Sockets;
    11. using Windows.Storage.Streams;
    12. using System.Threading.Tasks;
    13. using System.IO;
    14. using Windows.Networking;
    15. #endif
    16.  
    17.  
    18.  
    19. public class BroadcastReceiver : MonoBehaviour, IDisposable
    20. {
    21.     public static BroadcastReceiver instance;
    22.  
    23.     //OnMessageReceived
    24.     public delegate void AddOnMessageReceivedDelegate(string message, IPEndPoint remoteEndpoint);
    25.     public event AddOnMessageReceivedDelegate MessageReceived;
    26.     private void OnMessageReceivedEvent(string message, IPEndPoint remoteEndpoint)
    27.     {
    28.  
    29.         if (MessageReceived != null)
    30.         {
    31.             MessageReceived(message, remoteEndpoint);
    32.  
    33.         }
    34.     }
    35.  
    36. #if UNITY_EDITOR
    37.  
    38.     private Thread _ReadThread;
    39.     private UdpClient _Socket;
    40.  
    41. #else
    42.  
    43.     DatagramSocket _Socket = null;
    44.  
    45. #endif
    46.  
    47.     #region COMMON
    48.     string messageReceived = "";
    49.     public TMP_Text txtLog;
    50.     private bool isReceiving = false;
    51.  
    52.     private void Awake()
    53.     {
    54.         instance = this;
    55.     }
    56.  
    57.     private void Start()
    58.     {
    59.         Receive(9999);
    60.         InvokeRepeating("OnBtn_FreeMemory", 2, 5);
    61.     }
    62.     #endregion
    63.  
    64. #if UNITY_EDITOR
    65.  
    66.     public void Receive(int port)
    67.     {
    68.         if (isReceiving) return;
    69.  
    70.         isReceiving = true;
    71.  
    72.         // create thread for reading UDP messages
    73.         _ReadThread = new Thread(new ThreadStart(delegate
    74.         {
    75.             try
    76.             {
    77.                 _Socket = new UdpClient(port);
    78.                 Debug.LogFormat("Receiving on port {0}", port);
    79.             }
    80.             catch (Exception err)
    81.             {
    82.                 Debug.LogError(err.ToString());
    83.                 return;
    84.             }
    85.             while (true)
    86.             {
    87.                 try
    88.                 {
    89.                     // receive bytes
    90.                     IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
    91.                     byte[] data = _Socket.Receive(ref anyIP);
    92.  
    93.                     // encode UTF8-coded bytes to text format
    94.                     string message = Encoding.UTF8.GetString(data);
    95.                     OnMessageReceivedEvent(message, anyIP);
    96.                     messageReceived = message;
    97.  
    98.                 }
    99.                 catch (Exception err)
    100.                 {
    101.                     Debug.LogError(err.ToString());
    102.                 }
    103.             }
    104.         }));
    105.         _ReadThread.IsBackground = true;
    106.         _ReadThread.Start();
    107.     }
    108.  
    109.     public void Dispose()
    110.     {
    111.         if (_ReadThread.IsAlive)
    112.         {
    113.             _ReadThread.Abort();
    114.         }
    115.         if (_Socket != null)
    116.         {
    117.             _Socket.Close();
    118.             _Socket = null;
    119.         }
    120.         isReceiving = false;
    121.     }
    122.  
    123.  
    124. #else
    125.  
    126.     public async void Receive(int port)
    127.     {
    128.         if (isReceiving) return;
    129.  
    130.         isReceiving = true;
    131.    
    132.         string portStr = port.ToString();
    133.         // start the client
    134.         try
    135.         {
    136.             _Socket = new DatagramSocket();
    137.             _Socket.MessageReceived += _Socket_MessageReceived;
    138.  
    139.             await _Socket.BindServiceNameAsync(portStr);
    140.  
    141.             //await _Socket.BindEndpointAsync(null, portStr);
    142.  
    143.             //await _Socket.ConnectAsync(new HostName("255.255.255.255"), portStr.ToString());
    144.  
    145.  
    146.             //HostName hostname = Windows.Networking.Connectivity.NetworkInformation.GetHostNames().FirstOrDefault();
    147.             //var ep = new EndpointPair(hostname, portStr, new HostName("255.255.255.255"), portStr);
    148.             //await _Client.ConnectAsync(ep);
    149.  
    150.             Debug.Log(string.Format("Receiving on {0}", portStr));
    151.  
    152.             await Task.Delay(3000);
    153.             // send out a message, otherwise receiving does not work ?!
    154.             var outputStream = await _Socket.GetOutputStreamAsync(new HostName("255.255.255.255"), portStr);
    155.             DataWriter writer = new DataWriter(outputStream);
    156.             writer.WriteString("Hello World!");
    157.             await writer.StoreAsync();
    158.         }
    159.         catch (Exception ex)
    160.         {
    161.             _Socket.Dispose();
    162.             _Socket = null;
    163.             Debug.LogError(ex.ToString());
    164.             Debug.LogError(Windows.Networking.Sockets.SocketError.GetStatus(ex.HResult).ToString());
    165.         }
    166.     }
    167.  
    168.     private async void _Socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
    169.     {
    170.         try
    171.         {
    172.             Stream streamIn = args.GetDataStream().AsStreamForRead();
    173.             StreamReader reader = new StreamReader(streamIn, Encoding.UTF8);
    174.  
    175.             string message = await reader.ReadLineAsync();
    176.             IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.Parse(args.RemoteAddress.RawName), Convert.ToInt32(args.RemotePort));
    177.             OnMessageReceivedEvent(message, remoteEndpoint);
    178.             messageReceived = message;
    179.         }
    180.         catch (Exception ex)
    181.         {
    182.             Debug.LogError(ex.ToString());
    183.         }
    184.     }
    185.  
    186.     public void Dispose()
    187.     {
    188.         if (_Socket != null)
    189.         {
    190.             _Socket.Dispose();
    191.             _Socket = null;
    192.         }
    193.         isReceiving = false;
    194.     }
    195. #endif
    196.  
    197.     public void OnBtn_FreeMemory()
    198.     {
    199.         GC.Collect();
    200.         Resources.UnloadUnusedAssets();
    201.     }
    202.     public void OnBtn_StartSocket()
    203.     {
    204.         Receive(9999);
    205.     }
    206.     public void OnBtn_CloseSocket()
    207.     {
    208.         Dispose();
    209.     }
    210.  
    211.     void Update()
    212.     {
    213.         txtLog.text = messageReceived;
    214.     }
    215.  
    216.     private void OnDisable()
    217.     {
    218.         Dispose();
    219.     }
    220.  
    221. }
    222.  
    223.  
    224.  
    The problem seems to be this command

    Code (csharp):
    1.  
    2. Stream streamIn = args.GetDataStream().AsStreamForRead();
    3.  
    Do you have any idea on how could I fix this problem?
    Becouse after 30 sec of receiving data, the Application crash with "Out of memory".

    I've tried the same code also on a Lumia Phone and the problem still occur.

    Thanks in advance
     
  2. ivan20071

    ivan20071

    Joined:
    Nov 15, 2017
    Posts:
    29
    Hi Gabrio,
    I suggest you to dispose all disposable objects (Stream, StreamReader etc).

    Code (CSharp):
    1.                
    2. using (var streamIn = args.GetDataStream().AsStreamForRead())
    3.                 {
    4.                     using (var reader = new StreamReader(streamIn, Encoding.UTF8))
    5.                     {
    6.                         string message = await reader.ReadLineAsync();
    7.                         IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.Parse(args.RemoteAddress.RawName), Convert.ToInt32(args.RemotePort));
    8.                         OnMessageReceivedEvent(message, remoteEndpoint);
    9.                         messageReceived = message;
    10.                     }
    11.                 }
    12.  
    Ivan
     
  3. Gabrio

    Gabrio

    Joined:
    Jan 31, 2016
    Posts:
    17
    Thanks Ivan,
    already tried also with the using().
    It seems that the problem is Unity 2018 because I've tried now with 2017, same code, and all works correctly.
    The memory doesn't increase!!!
     
  4. ivan20071

    ivan20071

    Joined:
    Nov 15, 2017
    Posts:
    29
    Thanks Gabrio,
    good to know.
    Ivan
     
  5. centerforabcs

    centerforabcs

    Joined:
    Oct 2, 2018
    Posts:
    1
    I had the same problem with:

    Code (CSharp):
    1. Stream streamIn = args.GetDataStream().AsStreamForRead();
    Massive memory leak in IL2CPP build. Rewriting the message receiving code to not use the Stream class as in the example below eliminates the memory leak, tested in Unity 2018.2.18f1. I hope the problem is brought to the attention of the Unity QA team and promptly fixed.

    Code (CSharp):
    1. using (var reader = args.GetDataReader())
    2.         {
    3.             var buf = new byte[reader.UnconsumedBufferLength];
    4.             reader.ReadBytes(buf);
    5.             string message = Encoding.UTF8.GetString(buf);
    6.         }
     
    OliverVasvari and robot-ink like this.
  6. robot-ink

    robot-ink

    Joined:
    Jul 1, 2011
    Posts:
    18

    thankyou for posting this workaround. the memory leak is still an issue as of Unity 2019.2.0f1 :(
     
  7. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    Can you report a bug for this?
     
  8. rolfrudolfwolf

    rolfrudolfwolf

    Joined:
    Jul 1, 2018
    Posts:
    6
    For a future googler or whomever it might concern: We had the same problem in our UWP-UDP code on the Hololens2, Unity 2020.3.20f1, OpenXR 1.1.2, MRTK 2.7.2. The above workaround worked for us, thanks.
     
    corris_unity and asmarf6 like this.
  9. asmarf6

    asmarf6

    Joined:
    Jan 5, 2019
    Posts:
    1
    Thanks. I had the similar problem with HoloLens 2 and Unity version 2020.3.4f1 but I used this workaround by @centerforabcs . I tested it for more than 5 mins and the application didn't crash unexpectedly. I assume that this solution works !
     
    rolfrudolfwolf likes this.