即使释放了所有成员,垃圾收集器也不会检测到对象.TcpClient与此有关吗

本文关键字:检测 对象 与此有关 TcpClient 收集器 放了 释放 成员 | 更新日期: 2023-09-27 17:58:12

我知道发布长墙的代码是不好的,但这个问题看起来像是一个"浏览并看到一些东西"的问题。

我有一个名为Client的类,它包含了TcpClient所需的所有功能。它在自己的线程上运行,并在调用时使用由Dispose()触发的killSwitch变量。

我的问题是,即使在调用Dispose并丢失对该对象的引用之后,GC仍然不会捕获该对象,也不会删除该对象。

我如何测试对象创建/删除的示例:

private void TESTButton_Click(object sender, EventArgs e)
{
    System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient();
    tcp.Connect("127.0.0.1",3005);
    Client c = new Client(tcp, this);
}

类别定义:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Windows.Forms;
namespace v1_GameServer.GameServer
{
    public class Client : IDisposable
    {
        private Boolean gotCommunicatedInfo = false;
        private String username = "";
        private String password = "";
        private String ipAddress;
        private GameServerWindow window;
        private Boolean isDead;
        private static Int32 BUFF_SIZE = 1000;
        private byte[] buffer = new byte[BUFF_SIZE];
        private TcpClient connection;
        private NetworkStream stream;
        private Boolean thisThread_killSwitch = false;
        private readonly Thread thisThread;
        private List<object> packages = new List<object>();
        private object packages_lock = new object();
        private Client()
        { }
        public Client(TcpClient _connection, GameServerWindow win)
        {
            connection = _connection;
            stream = connection.GetStream();
            window = win;
            ipAddress = ((IPEndPoint)connection.Client.RemoteEndPoint).Address.ToString();
            isDead = false;
            thisThread = new Thread(new ThreadStart(HandleConnection));
            thisThread.Start();
            window.Post("+Client : " + ipAddress);
        }
        ~Client()
        {
            MessageBox.Show("TEST!");
            if (window != null)
                window.Post("-Client : " + ipAddress);
        }
        public void HandleConnection()
        {
            try
            {
                while (!thisThread_killSwitch && !isDead)
                {
                    int numBytes = stream.Read(buffer, 0, BUFF_SIZE);
                    if (numBytes > sizeof(Int32)) //Big enough to hold at least a type of message.
                    {
                        object newPackage = Package_Reader.ReadPackage(buffer, numBytes);
                        if (gotCommunicatedInfo == false)
                        {
                            if (newPackage is Package_Login_s)
                            {
                                username = ((Package_Login_s)newPackage).username;
                                password = ((Package_Login_s)newPackage).password;
                                gotCommunicatedInfo = true;
                            }
                            else
                            {
                                throw new InvalidOperationException("Received a package that was not login info from a new Client.");
                            }
                        }
                        else //(communicatedInfo == true)
                        {
                            lock (packages_lock)
                            {
                                if (newPackage != null)
                                    packages.Add(newPackage);
                            }
                        }
                    }
                    else if (numBytes == 0)
                    {
                        Dispose();
                    }
                }
            }
            catch (ObjectDisposedException e)
            {
                window.Post(ManagerForm.post_CLIENT_ERROR + "Client disconnected.");
                isDead = true;
            }
            catch (InvalidOperationException e)
            {
                window.Post(ManagerForm.post_CLIENT_ERROR + e.ToString());
                isDead = true;
            }
        }
        public object GetPackage()
        {
            lock (packages_lock)
            {
                if (packages.Count > 0)
                {
                    object pac = packages[packages.Count - 1];
                    packages.RemoveAt(packages.Count - 1);
                    return pac;
                }
                else
                    return null;
            }
        }
        public String GetUsername()
        {
            return (String)username.Clone();
        }
        public String GetPassword()
        {
            return (String)password.Clone();
        }
        public Boolean GetGotCommunicatedInfo()
        {
            return gotCommunicatedInfo;
        }
        public Boolean GetIsDead()
        {
            return isDead;
        }
        public String GetIP()
        {
            return (String)ipAddress.Clone();
        }
        public void Dispose()
        {
            thisThread_killSwitch = true;
            isDead = true;
            stream.Dispose();
            stream.Close();
            connection.Close();
            stream = null;
            connection = null;
            window = null;
        }
    }
}

即使释放了所有成员,垃圾收集器也不会检测到对象.TcpClient与此有关吗

您没有在Client类上正确实现IDisposable模式。您应该实现的模式是:

public class Foo : IDisposable
{
    private bool _disposed;
    ~Foo()
    {
        Dispose(false);
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // Dispose of managed resources
            }
            // Dispose of unmanaged resources
            _disposed = true;
        }       
    }
}

这样,无论是否调用Dispose()TcpClient实例最终都会被清理,不会导致资源泄漏。