SOCKET句柄泄露带来的内存灾难

博客讲述游戏出现大量内存泄露的排错过程。先排除游戏本身申请内存泄露,后发现是系统为进程申请的内存区域问题,通过PCHunter定位到是SOCKET创建句柄未释放导致,最终发现是第三方PING库代码只创建不关闭SOCKET所致。

前些时候游戏莫名其妙出现大量内存泄露,我感到很诧异,当然一般情况下游戏的内存管理是极其严苛的,出现如此大量的内存泄露到底是怎么回事?

句柄滥用导致的内存泄露会多夸张呢,尤其SOCKET,在某些客户端系统下,短短5个小时可以吃掉5GB以上内存,有甚者达到6GB,并且进程内存查看非常完好,并无激增,那内存去哪了?看看我们的排错过程。

1|0排错过程:

1、首先我们第一反应还是内存泄露,但是观察进程发现占用非常合理,并没有丝毫的激增情况,甚至运行周期后还会出现下降的情况,此类情况用资源管理器和性能管理器可以进行排错,从而进一步确定不是游戏本身所申请的内存泄露。

这里包含 MALLOC,NEW等方式。

为了安全期间,采用VLD进行内存泄露排错,预计结果和我猜测的一样,并无激增或泄露。

此处步骤必须,用于排除激增或可能存在激增的内存问题,在LINUX下有其他库请自己查找,至于此地由于是客户端泄露,采用的VLD库用于内存泄露排错。

2、其次我们发现是系统在申请并归属于该进程的一块内存区域,就像共享内存一样,此时已经初步认定为句柄未释放导致的内存泄露,那么如何定位?

首先要让内存产生泄露,然后请出PCHunter,启动后找到游戏目标进程,右键查看进程句柄。

此时可以看到句柄数已经非常异常,数量高达1182个之多,有些进程甚至过万,这是明显的异常,除非一般的服务端进程,通常情况下句柄数不会达到如此之数。

然后要定位是什么句柄导致的系统内存激增,通过数量分析发现有一项神奇过多:

File \Device\Afd 0x00000B38 0xFFFFE0005183E070 30 32758

此处的 \Device\Afd  为关键,该类型代表为SOCKET句柄,此处已经彻底定位到原因,是SOCKET创建句柄但未释放导致的异常。

3、以上方法已经定位到基本错误,确定是SOCKET,但是怎么知道是哪里呢,这就要监控所有SOCKET创建的地方,我这里是因为使用了第一个第三方的PING库,而这个库代码只创建SOCKET不关闭SOCKET。

所以产生以上问题,简单解决只要关闭不使用SOCKET即可解决,重点在于定位是异常难的,所以特写此文。

转自:SOCKET句柄泄露带来的内存灾难 - koangel - 博客园

<think>我们正在讨论socket句柄socket handle)在网络编程中的作用。根据用户的问题,用户希望了解关于socket句柄的技术信息,特别是与套接字操作和管理相关的内容。首先,我们需要明确socket handle是什么。在操作系统中,当应用程序创建一个套接字时,系统会返回一个套接字描述符(socketdescriptor),在Windows中通常称为句柄(handle),在Unix/Linux中称为文件描述符(filedescriptor)。这个句柄是一个整数,用于唯一标识该套接字。应用程序通过这个句柄来执行各种网络操作,如绑定、监听、连接、发送和接收数据等。 接下来,我们将按照以下结构组织回答: 1.什么是socket句柄? 2.如何创建和关闭socket句柄?3.使用socket句柄进行的基本操作(绑定、监听、连接、发送和接收等)。 4.管理多个socket句柄(如使用select、poll、epoll等I/O多路复用技术)。5.注意事项和最佳实践。我们将参考提供的引用内容,特别是引用[2]中关于套接字地址结构的说明,以及引用[3]和[4]中关于TCP和UDP套接字编程的示例。注意:由于用户要求使用中文回答,并且要求数学表达式使用$...$格式,但本问题中可能不涉及数学表达式,因此我们主要关注文本描述和代码示例。 现在开始编写回答:</think>### Socket句柄在网络编程中的技术解析 Socket句柄Socket Handle)是操作系统内核为每个套接字分配的唯一标识符,本质上是**文件描述符**(Unix/Linux)或**HANDLE对象**(Windows)。它在网络编程中扮演着核心角色,用于管理套接字生命周期和操作。 #### 一、Socket句柄的核心特性 1. **创建与销毁** - 创建:通过`socket()`系统调用返回整数型句柄 ```c int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP套接字 ``` - 销毁:调用`close()`(Unix)或`closesocket()`(Windows)释放资源 2. **句柄操作映射关系** | 操作类型 | 系统调用 | 句柄作用 | |----------------|--------------------------|----------------------------| | 地址绑定 | `bind(sockfd, ...)` | 指定套接字本地地址 | | 连接建立 | `connect(sockfd, ...)` | 发起TCP连接 | | 数据发送 | `send(sockfd, ...)` | 通过指定句柄传输数据 | | 多路复用 | `select()`/`epoll()` | 监控多个句柄的I/O事件 | 3. **内核层管理**(用户不可见) - 内核维护**套接字描述符表**,存储: ```mermaid graph LR A[Socket Handle] --> B[协议控制块] B --> C[发送缓冲区] B --> D[接收缓冲区] B --> E[状态机标记] ``` #### 二、关键操作技术细节 1. **地址绑定示例** ```python # Python示例(基于引用[3][^3]) import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('127.0.0.1', 8080)) # 通过句柄绑定地址 ``` 2. **多路复用监控** ```c // C语言select示例 fd_set readfds; FD_ZERO(&readfds); FD_SET(sockfd1, &readfds); // 添加句柄到监控集 FD_SET(sockfd2, &readfds); select(maxfd+1, &readfds, NULL, NULL, NULL); ``` 3. **资源泄漏风险** - 未关闭句柄导致: - 文件描述符耗尽(`EMFILE`错误) - 端口占用(`TIME_WAIT`状态累积) #### 三、最佳实践 1. **句柄管理原则** - 遵循**RAII模式**(资源获取即初始化) - 设置非阻塞模式:`fcntl(sockfd, F_SETFL, O_NONBLOCK)` 2. **现代多路复用技术** | 技术 | 优势 | 适用场景 | |------------|------------------------------|----------------| | `epoll` | $O(1)$事件复杂度 | Linux高并发 | | `kqueue` | 高效文件事件通知 | BSD系统 | | `IOCP` | 异步I/O完成端口 | Windows服务器 | 3. **错误处理规范** ```python try: data = sock.recv(1024) # 通过句柄操作 except socket.error as e: if e.errno == errno.EAGAIN: # 处理非阻塞模式下的重试 else: handle_error(e) finally: sock.close() # 必须显式关闭 ``` > **关键认知**:Socket句柄本质是**操作系统资源访问令牌**,其数值本身无意义,实际操作通过系统调用陷入内核,由内核根据句柄值查找对应的套接字数据结构[^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值