GpioPin上的事件处理程序导致垃圾收集器冻结应用程序

时间:2018-09-14 18:56:27

标签: c# raspberry-pi3 spi windows-10-iot-core windows-iot-core-10

我正在Raspberry Pi 3B上用C#编写Windows 10 IoT核心版的UWP应用程序,该应用程序应该与TI ADS1601 16位ADC交互。为了与该芯片进行通信,我必须对简单的类似于SPI的串行通信协议进行位敲打,然后首先通过及时发送的信号启动转换,如下图所示,摘自ADS1601手册:

enter image description here

为了初始化ADC,我必须根据晶体发生器的CLK(时钟信号)发送SYNC脉冲,并且从芯片读取有效响应后,就可以进行数据检索了。检测边缘是我开始遇到困难的地方。

我的代码受official Windows IoT Core GPIO example的直接启发:

// Open GPIO 27 - CLK (clock generator signal) listener
CLK2 = gpio.OpenPin(27);
CLK2.SetDriveMode(GpioPinDriveMode.Input);
CLK2.ValueChanged += EdgeDetCLKOnValueChanged; // event handler

事件处理程序如下:

private void EdgeDetCLKOnValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
    if (args.Edge.Equals(GpioPinEdge.FallingEdge))
        CLKedge = F_; //F_ == 0b11110000;
    if (args.Edge.Equals(GpioPinEdge.RisingEdge))
        CLKedge = _R; //_R == 0b00001111;
}

基本上,它只是设置了一个花式标记,指示发生了哪个边缘。在负责通信初始化的方法中正在使用和清除它。基本上,我将(我想使用)此类处理程序用于其他两个引脚的ValueChange事件。

所有这些(令牌,GpioPin实例,事件处理程序和init方法)都是同一公共类SimpleSerialProtocol的成员。 Whole code can be inspected here.

问题是,当附加事件处理程序并开始触发(因为它可以工作)时,垃圾收集器会发疯,并开始以太频繁的方式弹出,从而冻结整个应用程序。

enter image description here

  • 最上面的框显示内存使用情况,黄色点表示GC的出现。

在此项目中,我有CLK频率选择器,当我选择最低频率(约112Hz)时,应用程序排序工作正常(GC每5-10秒触发一次),但有时我从ADC接收到的数据帧会混乱。当我开始选择更高的频率时,GC会越来越频繁地弹出(这很有意义,因为GpioPin上的ValueChanged事件越来越频繁地被激发)到应用程序冻结和崩溃的地步。 我也可以用这张图片来说明这种行为,

enter image description here

摘自VisualStudio Performance Profiler测试。它代表大约30秒钟的空闲应用程序操作,左侧是存在(已订阅)ValueChanged处理程序,右侧是已注释掉的处理程序。另外,在左图中,所有其他活动都被过滤掉了,因此它可以以某种方式显示,并显示由垃圾收集器造成的破坏程度,用橙色条表示。

这个问题让我感到非常恐惧,因为我想所有垃圾回收的东西都是无限复杂的。您能帮我消除这种明显错误的行为吗?请原谅我的冗长的描述,我希望它尽可能紧凑,并且可以理解。

编辑

我从“内存使用情况”工具中获得了一些快照

enter image description here

并且显示了堆的状态,并总结了这些快照之间的对象/引用数量的差异(在将处理程序订阅ValueChanged之前,我使第一个处于空闲状态,而在使用这些处理程序的各个操作中,又有四个)。 >

在差异列表中,大多数差异都在 RuntimeType 对象中,当我选择此项以获得更多详细信息时,该短语位于列表顶部:

Object [](固定访问)(它以波兰语显示,所以我尝试翻译它可能是错误的)。

但是,我现在不明白这可能意味着什么,而且我找不到关于该对象的任何更具体的信息(例如对我的代码的一些引用)。

0 个答案:

没有答案