This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] RTOS/TM4C129ENCZAD:拉动以太网电缆时、关闭插槽不会清理所有动态内存、从而导致内存泄漏

Guru**** 2473260 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/659443/rtos-tm4c129enczad-when-ethernet-cable-is-pulled-closing-sockets-does-not-clean-up-all-dynamic-memory-causing-memory-leak

器件型号:TM4C129ENCZAD

工具/软件:TI-RTOS

我正在调查 Tiva 微控制器的内存泄漏问题。

微控制器是 TCP 服务器。  客户端与 微控制器建立 TCP 连接。  当 TCP 套接字仍处于啮合状态时、请从 Launchpad 取出以太网电缆。  此时、微控制器检测到以太网丢失、并尝试通过关闭插槽来清理。  但是、并非所有存储器都被回收、4112字节丢失。  TCP 发送缓冲区为2048字节、TCP 接收缓冲区也为2048字节。  因此、丢失的内存比 TCP 发送和接收缓冲区多16字节。  另一个问题是、当再次插入以太网电缆时、我无法再在相同的端口号上建立 TCP 服务器、我必须使用另一个端口号。

我已验证、如果客户端在拔下以太网电缆之前断开与插座的连接、则不会丢失内存。  我还确保在检测到以太网链路丢失时也调用 fdlose。   

我在 TI Launchpad 上运行的小型应用中重新创建了相同的错误。  请帮助。   e2e.ti.com/.../NDKTest.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Yan、

    感谢您提供示例! 我将查看它并返回给您。

    Todd
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Yan、

    我运行了您的示例。 我没有看到内存泄漏。 我正在检查 ROV->HeapMem->Detailed before and after unplugging,and then again。 如何确定泄漏? 我附加了一个文件、其中包含 CCS 控制台输出以及中添加的 HeapMem 自由大小。

    e2e.ti.com/.../HeapMemFree.txt

    Todd

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我使用 ROV 来查看内存泄漏。  从您的日志中、我看到您未连接客户端。  在客户端仍然连接的情况下拔下电缆时、内存会丢失。  我使用 Hercules 连接到 launchpad。  您可以使用任何 TCP 客户端、行为将是相同的。  我已从我的跑步记录中附加了一个日志。

    e2e.ti.com/.../HeapMemLeak.txt

    Yan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我会尝试一下、但您能给我提供有关如何连接客户端的确切说明吗? 我不知道什么是 Hercules。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

     附件是应用程序的图像。  它只是一个 TCP 测试工具:

    1.打开程序

    2.选择 TCP 客户端选项卡。  我在随附的照片中用红色圆圈标出

    3.在模块 IP 框中,输入分配 launchpad 的 IP 地址。  从您的日志中、应该是146.252.162.135

    4.在 Port (端口)框中,输入10700。

    5.现在按 Port (端口)框下方的 Connect (连接)按钮。

    6.您应该看到:以太网 TCP -客户端已连接。 地址=... 输出中的值

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    能否从附加文件中提取可执行文件?e2e.ti.com/.../HerculesSetup.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Yan、

    我将获得不同的结果。 有时我会看到内存泄漏、但我无法获得一致的运行。 我已启用 HeapTrack 来查看何时以及谁分配了泄漏的块。 要启用、只需将以下内容添加到.cfg 中即可:

    BIOS.heapTrackEnabled = true;

    然后,在 Tools->ROV->HeapTrack->HeapAllocList 中,您可以看到当前分配的块、该块的线程以及分配发生时的时钟节拍。 我还将 TCP/UDP Rx/Tx 大小更改为唯一值(例如、其中一个为2048+64、另一个为20488-64等)、以帮助确定哪个分配是哪一个分配。 您也可以尝试进行此操作、看看它是否有助于您进行调试。 您可以使用 ROV->Tasks->Basic 来确定哪个任务是哪个任务。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Todd、

    BIOS.heapTrackEnabled = true;是一个很好的诀窍。  下次遇到内存泄漏时、我将使用该方法。

    从您的图像中、我看到您已将缓冲区大小更改为1920和1984。  这与0x7c8和0x788的分配相匹配。  仅当连接了插槽时、才会发生内存泄漏。  第一次拔下插头时、我始终会看到内存泄漏。  通常也会在第二个插头上看到它。  当您拔下并重新插上连接的插座时、您应该会看到

    00069.600 TcpTimeoutRexmt:重新发送超时

    "已创建以太网 TCP 套接字。 端口号= 10071。"

    此时、旧端口号10070无法再使用、在 Hercules 应用中、您需要连接到新端口号10071。   

    我按照您的建议将配置文件中的 TCP 发送缓冲区大小更改为1984、并将接收保留为2048。  现在、我看到内存泄漏大小为(1984 + 8)和(2048 + 8)。  拔下电缆3次后捕获连接的映像、8096字节已泄漏。  从图中可以看出、发送和接收缓冲区都没有被释放。  当我调用 fdClose 时、NDK 应释放内存、因此我认为这是 NDK 本身的问题。  

    您能解决这个问题吗?

    谢谢你。

    -Yan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您能否提供您看到的控制台输出。 我无法第二次连接(使用10071或10070)。 在这里、我在重新插入电缆后看到的是:

    已创建以太网 UDP 套接字。 端口号= 10065。

    错误-无法打开以太网 TCP 套接字。 无法绑定到套接字。 端口号= 10070。 ERR = 0x30

    已创建以太网 TCP 套接字。 端口号= 10071。

    已创建以太网套接字。 端口号= 10071。

    Etherent TCP 客户端已断开连接。 ADDR = 0x0

    注:在重新插入电缆之前或之后、我不会手动断开客户端。

    我们在 NDK 中修复了一个错误。 您能否尝试此修复并重建 NDK (并重新链接应用程序)以查看此修复是否有用。  

    e2e.ti.com/.../sockpcb.c

    只有几行不同。 该文件位于 C:\ti_tirtos_tivac_2_12_01_33\products\NDK_2_24_02_31\packages/ti\NDK\stack\sock\sockppcb.c 中

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    拉动电缆后、您可以在电缆再次插入之前或之后单击 Hercules 上的断开按钮。  由于链路断开、因此无关紧要:

    以太网 TCP 端口已关闭

    以太网电缆已拔下

    网络已删除:IF-1:10.40.1.82

    以太网状态报告0x5、0x0、0x0

    服务状态:DHCP:  已禁用:      :000

    DisableNDKDHCP 成功

    重新插入电缆后:

    错误-无法打开以太网 TCP 套接字。 无法绑定到套接字。 端口号= 10070。 ERR = 0x30

    已创建以太网 TCP 套接字。 端口号= 10071。

    已创建以太网套接字。 端口号= 10071。

    Etherent TCP 客户端已断开连接。 ADDR = 0x0

    现在将 Hercules 中的端口号更改为10071、然后单击"Connect":  

    "客户端请求检测到以太网 TCP -客户端已连接。 地址= 10.40.1.200

    套接字已连接"

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Todd、

    关于 NDK 文件、我在这里找到了该文件:C:\ti_tirtos_tivac_2_12_01_33\products\new_ndk_2_24_02_31\packages/ti\ndk\stack\sock\sockppcb.c

    但是、我不知道如何重新编译。 我只向我的项目添加了 NDK 包含路径、而没有包含 NDK 库。 是否有 NDK 的库文件? 如何编译 NDK 并将工程链接到新库?

    -Yan
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    请查看 TI-RTOS 用户指南。 有一个有关重建的部分。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我按照指令重建了 RTOS -花费了几分钟时间。  仍然存在相同的问题。  应用新 的 sockpcb.c 后、您是否会发现此问题消失?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我将请其中一位 NDK 工程师来看看这一点。 可能需要一两天的时间才能得到响应。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Yan、

    我只是想向大家介绍一下、我正在审查和重现此问题。 我将在收到更多信息后再发布到这里。

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Steve、

    对此进行了任何更新?

    谢谢。

    -Yan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Yan、

    我还没有太多的更新、但至少要让您知道我没有忘记这个问题。

    我们能够在本地运行您的应用程序、但尚未发现问题。 周一、我们将跟踪 Todd、让他进行回顾、并确保我们的工作正常。

    只是为了与您确认,我们在代码中设置断点,并在 ROV 中检查堆,使用输出日志作为指导(基本上,我们在您添加的部分放置断点)。 >"在附加的日志文件中键入注释)。 如果您确认这对您来说是正确的、这将会有所帮助。

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Steve、

    只要每次在 ROV 中检查堆时在同一个点进行中断、将断点置于何处无关紧要。  重新创建的步骤会在该主题中发布。  摘要如下:

    1.建立与 Launchpad 的 TCP 连接。 在 ROV 中对堆进行采样。

    2.支架式输出以太网电缆。

    3.重新插入以太网电缆

    4.建立 与 Launchpad 的 TCP 连接。 再次在 ROV 中对堆进行采样、并注意堆已减少。

    拔出以太网电缆时、确保仍建立 TCP 连接。

    -Yan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Yan、

    好的、我认为我们在这里看到了一个问题、尽管我们在这里看到的是接近2K 的、看起来是泄漏的。

    我将深入探讨这一点、一旦我发现更多信息、我就会告诉您。

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Steve、

    很好、您可以重现此问题。  请随时向我发布。 我在某个时候确实需要对此进行修复。

    -Yan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Yan、

    我终于能够回到这个问题。 我添加了一些调试代码以打印套接字表、以查看发生了什么情况。

    我看到的是、由于拔下并重新插入电缆、删除并重新添加 IP 地址后、原始 TCP 套接字(您必须连接到该套接字才能重现问题)仍然挂起。

    当您在该套接字上调用 Close 时、它将进入 TCP 的 Close 阶段。 在这种情况下、由于您在其上发出 Close 命令、这会导致激活 Close 命令。 然后、插座进入 TIMEWAIT 状态、等待 MSL 的2倍、该时间应为60秒。

    因此、我认为我们在这里没有看到内存泄漏、而是插槽和其资源实际上尚未释放、因为插槽被保持在 TIME_WAIT 状态。

    我得到的输出的以下摘录显示了该问题。 请注意、输出将显示套接字处于 FINWAIT1状态、而不是 TIME_WAIT 状态、但请放心、我确实看到套接字进入 TIME_WAIT 状态。 (之所以显示 FINWAIT1、是因为我主动停止目标、并且很可能错过了客户端的 ACK + FIN/ACK、这会导致实际转换到 TIME_WAIT。 此外、有关完整输出、请参阅此消息的末尾):

    本地 IP LPort Foreign IP (端口外部 IP) FPort 状态
    --- ---- -------- ---- ------
    0.0.0.0 0 0.0.0.0 0 已关闭
    146.252.162.135 10070 146.252.162.253 62381 FINWAIT1
    

    关于端口错误消息、这同样是因为同一套接字仍然存在。 当您尝试使用相同的端口创建新套接字时、原始套接字仍然存在(处于 TIME_WAIT 状态)、因此您会收到该端口已在使用的错误消息。

    供参考-我最近帮助另一位客户解决了更改 IP 地址时出现的一些问题。 其结果是、用于要删除的 IP 地址的所有套接字现在都被强制关闭、因为当删除 IP 地址或关闭堆栈等非常严重的内容时、这些套接字应该不再有效。

    如果您对此感兴趣、请参阅 此主题、其中包含一个补丁 以及如何使用该补丁更新重建 NDK 的步骤。

    Steve

    EPHY_BMCR = 0x0
    BMSR = 0x7849
    EPHY_ANA = 0x1e1
    EPHY_ANLPA = 0x0
    EPHY_STS = 0x2
    主机通信任务已启动。 正在启动消息交换
    以太网状态报告0x5、0x4、0x0
    服务状态:DHCP:已启用: :000
    以太网 DHCP 客户端已启动
    服务状态:DHCP:已启用:正在运行:000
    StartNDKDHCP: DHCP 条目已存在。 尝试删除
    以太网状态报告0x5、0x0、0x0
    服务状态:DHCP:已禁用: :000
    以太网状态报告0x5、0x4、0x0
    服务状态:DHCP:已启用: :000
    起始 DHCP
    以太网 DHCP 客户端已启动
    服务状态:DHCP:已启用:正在运行:000
    网络已添加:if-1:146.252.162.135
    以太网 DHCP IP 地址已添加
    服务状态:DHCP:已启用:正在运行:017
    以太网 IP 地址已添加:创建146.252.162.135
    以太网 UDP 套接字。 端口号= 10065。
    以太网:OpenTCPSocket (),打印套接字表
    
    
    
    已创建以太网 TCP 套接字。 端口号= 10070。
    
    
    已创建以太网套接字。 端口号= 10070。
    以太网 TCP -客户端已连接。 ADDR = 146.252.162.253
    以太网:TCPAccept(),打印套接字表
    
    插座连接
    的以太网 TCP 端口闭合
    的以太网电缆已拔出
    关闭
    
    
    的本地 IP LPort Foreign IP (端口外部 IP) FPort 状态
    --- ---- -------- ---- ------
    146.252.162.135 10070 146.252.162.253 62381建立
    了146.252.162.135 10070 0.0.0 0 侦听
    
    
    本地 IP LPort Foreign IP (端口外部 IP) FPort 状态
    --- ---- -------- ---- ------
    146.252.162.135 10070 146.252.162.253 62381建立
    了146.252.162.135 10070 0.0.0 0 侦听
    
    网络已删除:IF-1:146.252.162.135
    以太网状态报告0x5、0x0、0x0
    服务状态:DHCP:已禁用: :000
    DisableNDKDHCP 成功
    
    
    以太网状态报告0x5、0x4、0x0
    
    本地 IP LPort Foreign IP (端口外部 IP) FPort 状态
    --- ---- -------- ---- ------
    146.252.162.135 10070 146.252.162.253 62381 FINWAIT1
    
    服务状态:DHCP: Enabled: :000
    启动 DHCP
    以太网 DHCP 客户端已启动
    服务状态:DHCP:已启用:正在运行:000
    00029.000 TcpTimeoutRexmt:重新发送超时
    00029.600 TcpTimeoutRexmt:重新发送超时
    00031.600 TcpTimeoutReximt:重新发送超时
    网络已添加:if-1:146.252.162.135
    以太网
    DHCP IP 地址已添加服务状态:已启用
    以太网 DHCP IP 地址:已启用:已添加以太网 IP 地址:
    创建了146.252.162.135以太网 UDP 套接字。 端口号= 10065。
    以太网:OpenTCPSocket (),打印套接字表
    
    
    
    错误-无法打开以太网 TCP 套接字。 无法绑定到套接字。 端口号= 10070。 ERR = 0x30
    以太网::OpenTCPSocket (),打印套接字表
    
    
    
    已创建以太网 TCP 套接字。 端口号= 10071。
    
    
    已创建以太网套接字。 端口号= 10071。
    Etherent TCP 客户端已断开连接。 ADDR = 0x0
    以太网 TCP 端口闭合
    以太网电缆拔出
    0 0.0.0.0 0 已关闭
    146.252.162.135 10070 146.252.162.253 62381 FINWAIT1
    
    
    本地 IP LPort Foreign IP (端口外部 IP) FPort 状态
    --- ---- -------- ---- ------
    146.252.162.135 10071 0.0.0.0 0 已关闭
    0.0.0.0 0 0.0.0.0 0 已关闭
    146.252.162.135 10070 146.252.162.253 62381 FINWAIT1
    
    00038.800 TcpTimeoutRexmt:重新发送超时
    00048.400 TcpTimeoutRexmt:重新发送超时
    网络已删除:if-1:146.252.162.135
    以太网状态报告0x5、0x0、0x0
    服务状态:DHCPPC:已禁用:已禁用: :000
    DisableNDKDHCP 成功
    
    本地 IP LPort Foreign IP (端口外部 IP) FPort 状态
    --- ---- -------- ---- ------
    0.0.0.0 0 0.0.0.0 0 已关闭
    146.252.162.135 10070 146.252.162.253 62381 FINWAIT1
    
    
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    下面是更新后的项目、它将显示套接字表打印出来。

    有关代码、请参阅项目中的 SockUtils.c/h。

    Steve

    e2e.ti.com/.../NDKTest_5F00_SockUtils.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    MSL 是什么?是否有减少 MSL 的方法?  强制关闭所有套接字的代码听起来很有趣。  下周我将对此进行验证。   感谢 Steve。   

    -Yan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    MSL 是最长段寿命。

    您可以更改它、但我不推荐它。 这样做可能会对 TCP 造成不良影响。

    如果您仍想更改它,则您有代码,我无法阻止您:)... 但请注意、您将自行承担以下风险:

    // ti/ndk/stack/TCP/tcp.h
    #define TCPTV_MSL 300

    (这需要重建堆栈)

    Steve
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Yan、

    您是否有机会验证此问题? 我可以将其标记为已解决吗?

    Todd
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Todd、

    我在周五终于能做到这一点、但在我为您获取日志和屏幕截图之前中断了。  我在周五重建了 NDK、尝试了新库、但没有发现任何行为差异。  我将在今天晚些时候或明天为您获取日志。

    -Yan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是否所有运行 NDK 的器件都容易受到此内存泄漏的影响?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Todd、

    我在 NDK v2.224.02.31中运行 tirtos_tivac_2_12_01_33、并验证了软件包子目录中的所有.aem4f 文件都具有星期五4/13日期戳、因此我相信 NDK 构建成功。

    我必须更改几行代码、以便客户可以再次连接。  e2e.ti.com/.../NDKTest_5F00_v2.zip

    1.堆内存始终在 host_comm.cpp 行26 (NetworkInterface::MainainLink())上采样。 当程序首次运行且首先创建以太网套接字时、堆位于0xee40:

    2. TCP 客户端已连接、堆降至0xde50:

    3.以太网电缆被拉、堆重新恢复到0xF5e8

    4.重新插入网线。  堆降至0xd690、低于先前 的0xde50值:

    5、经过3次迭代后、堆已降至0xae20。 因此、内存泄漏是永久性的、而不是暂时性的。