烽燧煜明 2025-09-30 14:46 采纳率: 75%
浏览 14
已结题

分析内存的时候一直看见内存在往上涨,但用分析工具除了这个“未解析的分配”以外什么也看不见

img


分析内存的时候一直看见内存在往上涨,但用分析工具除了这个“未解析的分配”以外什么也看不见

img


堆栈里面也只能看到一个“自动”

2025-10-12
这是代码的主体部分
核心思想是用tcp协议做内部的设备时间同步
客户端会给我一个心跳包
这时候我会记录心跳包的时间,然后等第二次发心跳包的时候计算间隔
如果小于设定值就不做操作等待下一次
如果超过设定值就会向客户端发送服务端的当前时间,进行时间同步

using CYQ.Data;
using CYQ.Data.Json;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace TimeSyncConsoleApp
{
    public class TimeSyncServerClass
    {
        private static Dictionary<string, DateTime> _deviceTimeList = new Dictionary<string, DateTime>();
        public static TimeSyncForm timeSyncForm;
        private static bool finishFlag = false;

        private static Dictionary<string, DateTime> DeviceTimeList { get => _deviceTimeList; set => _deviceTimeList = value; }
        //private static System.Timers.Timer TimeSyncTimer { get; set; }

        public static void Init()
        {
            timeSyncForm = new TimeSyncForm();
        }

        /// <summary>
        /// 启动监听进程
        /// </summary>
        public static void StartListening()
        {
            try
            {
                Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                ushort port = Convert.ToUInt16(TimeSyncHelperClass.GetAppSettingsValue("ServerPort"));
                tcpServer.Bind(new IPEndPoint(IPAddress.Any, port));        //绑定IP和端口号
                tcpServer.Listen(backlog: 100);      //将套接字的监听队列长度限制为100

                Thread listenThread = new Thread(ListeningClients)
                {
                    IsBackground = true,
                };
                listenThread.Start(tcpServer);
            }
            catch (Exception ex)
            {
                Log.WriteLogToTxt($"[{DateTime.Now:u}] {ex}", LogType.Error);
                PrintData($"[{DateTime.Now:u}] {ex}");
            }
        }

        /// <summary>
        /// 监听客户端请求
        /// </summary>
        /// <param name="serverSocketObj"></param>
        private static void ListeningClients(object serverSocketObj)
        {
            using (Socket serverSocket = serverSocketObj as Socket)
            {
                while (true)        //持续不断监听客户端发来的请求
                {
                    try
                    {
                        Socket clientSocket = serverSocket.Accept();        //暂停当前线程,直到有一个客户端连接过来
                        Thread listenThread = new Thread(HeartBeat)
                        {
                            IsBackground = true,
                        };
                        listenThread.Start(clientSocket);
                        if(finishFlag)
                        {
                            listenThread.Abort();
                            finishFlag = false;
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteLogToTxt($"[{DateTime.Now:u}] {ex}", LogType.Error);
                        PrintData($"[{DateTime.Now:u}] {ex}");
                    }
                }
            }
        }

        /// <summary>
        /// 心跳包维持通信通道
        /// </summary>
        /// <param name="clientSocketObj"></param>
        private static void HeartBeat(object clientSocketObj)
        {
            using (Socket clientSocket = clientSocketObj as Socket)
            {
                clientSocket.ReceiveTimeout = TimeSyncHelperClass.TimeoutSecCounts;
                Log.WriteLogToTxt($"[{DateTime.Now:u}] Connected:\r\n{clientSocket.RemoteEndPoint}");
                PrintData($"[{DateTime.Now:u}] Connected:\r\n{clientSocket.RemoteEndPoint}");
                try
                {
                    string getMessage = ReceiveData(clientSocket);
                    if (IsBox(getMessage, out string deviceKey))
                    {
                        string heartbeatReply = "HelloZbbox";
                        SendData(clientSocket, heartbeatReply);

                        if (deviceKey.Length != 0 && deviceKey != null)
                        {
                            //加锁并检查时间
                            lock (DeviceTimeList)
                            {
                                if (!DeviceTimeList.ContainsKey(deviceKey))
                                {
                                    DeviceTimeList.Add(deviceKey, DateTime.Now);
                                }
                                else
                                {
                                    double updateFrequency = (int)CustomTimeTypesEnum.Minute * Convert.ToInt32(TimeSyncHelperClass.GetAppSettingsValue("TimeSyncMinutesInt"));
                                    double timespan = (DateTime.Now - DeviceTimeList[deviceKey]).TotalMilliseconds;
                                    if (timespan > updateFrequency)
                                    {
                                        string setTimeSendData = $"@ZbboxPackType=1&ZbSetDate={DateTime.Now:yyyy-MM-dd}&ZbSetTime={DateTime.Now:HH:mm:ss}!";
                                        SendData(clientSocket, setTimeSendData);
                                        //StringBuilder resultString = new StringBuilder(ReceiveData(clientSocket));
                                        _ = ReceiveData(clientSocket);
                                        DeviceTimeList.Remove(deviceKey);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.WriteLogToTxt($"[{DateTime.Now:u}] {ex}", LogType.Error);
                }
                finally
                {
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close();
                    Thread.Sleep(100);
                    finishFlag = true;
                }
            }
        }

        /// <summary>
        /// 向客户端发送数据
        /// </summary>
        /// <param name="sendClient"></param>
        /// <param name="sendData"></param>
        private static void SendData(Socket sendClient, string sendData)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(sendData);
            Log.WriteLogToTxt($"[{DateTime.Now:u}] Sending:\r\n{sendData}");
            PrintData($"[{DateTime.Now:u}] Sending:\r\n{sendData}");
            sendClient.Send(bytes);
            Thread.Sleep(100);
        }

        /// <summary>
        /// 从客户端读取数据
        /// </summary>
        /// <param name="sendClient"></param>
        /// <returns></returns>
        private static string ReceiveData(Socket sendClient)
        {
            byte[] buffer = new byte[(int)CustomBufferSizeEnum.KB * 2];
            try
            {
                sendClient.Receive(buffer);
            }
            catch (SocketException ex)
            {
                Log.WriteLogToTxt($"[{DateTime.Now:u}] {ex}", LogType.Warn);
                PrintData($"[{DateTime.Now:u}] {ex}");
            }
            catch (Exception ex)
            {
                Log.WriteLogToTxt($"[{DateTime.Now:u}] {ex}", LogType.Error);
                PrintData($"[{DateTime.Now:u}] {ex}");
            }
            List<byte> result = new List<byte>();
            for (int j = 0; j < buffer.Length; j++)
            {
                if (buffer[j] != 0)
                {
                    result.Add(buffer[j]);
                }
            }
            if (result.Count > 0)
            {
                string streamString = Encoding.UTF8.GetString(result.ToArray());
                Log.WriteLogToTxt($"[{DateTime.Now:u}] Recieved:\r\n{streamString}");
                PrintData($"[{DateTime.Now:u}] Recieved:\r\n{streamString}");
                string resultString = streamString.Replace("@", "{\"").Replace("!", "\"}").Replace("&", "\",\"").Replace("=", "\":\"");
                Log.WriteLogToTxt($"[{DateTime.Now:u}] Processed:\r\n{resultString}");
                PrintData($"[{DateTime.Now:u}] Processed:\r\n{resultString}");
                return resultString;
            }
            else
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 判断是不是设备
        /// </summary>
        /// <param name="messageString"></param>
        /// <param name="deviceId"></param>
        /// <returns></returns>
        private static bool IsBox(string messageString, out string deviceId)
        {
            if (JsonHelper.IsJson(messageString))
            {
                try
                {
                    Dictionary<string, string> dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(messageString);
                    if (dict["ZbboxPackType"] == "0")
                    {
                        deviceId = $"{dict["ZbboxName"]}_{dict["ZbboxLocation"]}";
                        return true;
                    }
                    else
                    {
                        deviceId = string.Empty;
                        return false;
                    }
                }
                catch (Exception)
                {
                    deviceId = string.Empty;
                    return false;
                }
            }
            else
            {
                deviceId = string.Empty;
                return false;
            }
        }

        /// <summary>
        /// 在界面上显示日志
        /// </summary>
        /// <param name="data"></param>
        public static void PrintData(string data)
        {
            if (timeSyncForm.PrintDataAction != null)
            {
                timeSyncForm.Invoke(timeSyncForm.PrintDataAction, data);
            }
        }
    }
}


  • 写回答

6条回答 默认 最新

  • wanghui0380 2025-09-30 17:20
    关注

    图上已经看不出来了,从截图代码上看,timesync--时间同步。
    所以我只能猜测你有个timer,在不停触发什么什么同步方法,而且这个方法要不就是执行时间比timer定时还长(注1),要么就是内部没有处理好对象释放(注2 )

    哎非说有代码,我只能加代码框了

    1:那是生产大于消费问题,如果不是长很多,最终会形成一个比较稳定的内存,参考小学那个进水,放水问题。 一开始会堆积一点内存,最后水位稳定。当然如果你生产越越大于消费,那就水满金山了。
    解决方法:a:信号量限流,最大允许10个。超出10个直接忽略执行要求。
                     b。使用公共池化对象,也是限制10个,借出对象再用,用完归还。借不到请等待
    如果这样内存在持续一段时间后都不能稳定在一个平衡“水位”,拿就是楼上那几个机器人说的,对象有泄露了。
    
    注2:对象泄露,就得检查代码了是否及时解除引用计数,是否引用了些第3方的标准dll,是否按照人家规定要求及时释放对应内存了。还有就是你是否自己缓存到一些全局对象了,比如你这里我还看到了一个form窗体,你是否在给这个窗体不停推数据,他是否在不停的绘制图表或者不停的把结果加入到某个datagridview列表里。
    
    
    
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

问题事件

  • 系统已结题 10月21日
  • 已采纳回答 10月13日
  • 修改了问题 10月12日
  • 创建了问题 9月30日