【发布时间】:2023-03-03 19:01:01
【问题描述】:
我不确定我在这里做错了什么。虽然我对 C# 并不陌生,但我从未使用它来访问 GPIO,也没有部署到 Linux。
它在 Raspberry Pi 3 B+ 上运行,使用 dotnet 6.0。启动时,它使用了近 200MB 的虚拟内存,其中 71 个是私有的。它运行了一天多一点并崩溃。我已经查看了内存泄漏的主要原因,并试图一遍又一遍地优化它,它的大小仍在增长,直到它出现 OOM 错误。看起来很简单,但它每 4-5 分钟增长约 1 MB。
在我的 Main() 函数中,我有这个:
while (true) {
var TH = new TempHumidity();
TH.RefreshSensorData();
TH = null;
Thread.Sleep(500);
counter++;
if (counter == 10) {
GC.Collect();
counter = 0;
}
}
这是它正在调用的函数。我曾经将它作为公共静态,然后转移到私有。我意识到我可以减慢 while 循环的速度,但泄漏发生的速度越快,调试起来就越容易。理想情况下,这将能够无限期地运行,因此任何泄漏最终都会对我的宠物造成致命伤害。
using System;
using System.Collections.Generic;
using Iot.Device.DHTxx;
namespace TempControl
{
public class TempHumidity
{
public static List<Sensor> SensorData = new List<Sensor>();
public void RefreshSensorData()
{
int[] pins = new int[] { 10, 9, 11, 5, 6, 13, 19, 26 };
var TH = new TempHumidity();
foreach (var pin in pins)
{
try
{
TH.GetPinData( pin);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
private void GetPinData(int pin) {
using (Dht11 dht = new Dht11(pin))
{
double testVal = dht.Temperature.DegreesFahrenheit;
if (dht.IsLastReadSuccessful)
{
bool foundMatch = false;
foreach (var sensor in SensorData)
{
if (pin == sensor.pin)
{
foundMatch = true;
sensor.humidity = dht.Humidity.Percent;
sensor.temperature = dht.Temperature.DegreesFahrenheit;
if (sensor.maxTemp < dht.Temperature.DegreesFahrenheit)
{
sensor.maxTemp = dht.Temperature.DegreesFahrenheit;
}
if (sensor.minTemp > dht.Temperature.DegreesFahrenheit)
{
sensor.minTemp = dht.Temperature.DegreesFahrenheit;
}
if (sensor.maxHumidity < dht.Humidity.Percent)
{
sensor.maxHumidity = dht.Humidity.Percent;
}
if (sensor.minHumidity > dht.Humidity.Percent)
{
sensor.minHumidity = dht.Humidity.Percent;
}
sensor.last_updated = DateTime.Now;
sensor.reading_good = true;
}
}
if (foundMatch == false)
{
Sensor currentSensor = new Sensor();
currentSensor.pin = pin;
currentSensor.temperature = dht.Temperature.DegreesFahrenheit;
currentSensor.humidity = dht.Humidity.Percent;
SensorData.Add(currentSensor);
currentSensor = null;
}
}
else
{
foreach (var sensor in SensorData)
{
if (pin == sensor.pin)
{
var TimeNow = DateTime.Now;
int diff = Convert.ToInt32(TimeNow.Subtract(sensor.last_updated).TotalSeconds);
if (diff > 3)
{
sensor.reading_good = false;
}
}
}
}
}
}
public class Sensor
{
public string id { get; set; }
public int pin { get; set; }
public double temperature { get; set; }
public double humidity { get; set; }
public DateTime last_updated;
public DateTime last_reported;
public double minTemp = 200;
public double minHumidity = 200;
public double maxTemp = 0;
public double maxHumidity = 0;
public bool reading_good = false;
public bool relay_on = false;
}
public class SensorList
{
public List<Sensor> data { get; set; }
}
}
}
我几乎禁用了所有其他代码执行区域,这实际上只是基于这些读数的继电器控制。我不确定我的问题是使用了一个有内存泄漏的坏包,还是我没有正确地做事。
【问题讨论】:
-
你不应该像那样调用 GC.Collect,你可能会匆忙 GC,将对象推入 Gen1 和 Gen2 太快。同样,在变量超出范围之前立即将它们设置为 null 是没有用的(尽管这很难咬你)。您是否检查过您的代码并确保 Dispose 每个一次性对象?我通常的建议是使用 PerfMon 中的 .NET 内存计数器来帮助您弄清楚发生了什么。用锉刀。可能是无用的 PI。
-
GC.Collect();是否一直在您的代码中,或者您是否添加了它以尝试解决问题? -
谢谢大家,我刚刚添加了
GC.Collect();来清理它。 @ Flydog57 我不知道我拥有的任何东西都是一次性的,这不是我过去不得不担心的事情。实际上,我的执行代码的每一部分都已经显示出来了,所以如果你看到我应该处理的东西,请告诉我。 -
一般来说,任何做 I/O 的东西都是一次性的(只是因为)。我猜你用 Raspberry PI 做的几乎所有事情都是在做 I/O。
-
访问 GPIO 的库已经在 using 语句中,所以我认为它会正确 GC,但我在最后添加了一个 .Dispose() 以进行良好的衡量。运行 15 分钟后,它仍然增长了 3MB
标签: c# .net-core memory-leaks raspberry-pi gpio