Утечка памяти при использовании NetFwTypeLib в .Net Core 3.1C#

Место общения программистов C#
Anonymous
Утечка памяти при использовании NetFwTypeLib в .Net Core 3.1

Сообщение Anonymous »

Я обнаружил утечку памяти в консольном приложении мониторинга трафика IDS/IPS, над которым я работал. Я думал, что это инфраструктура объектов, оказалось, это код брандмауэра. Следующий код отлично работал в .net 4.6.2 и в основном отлично работает в ядре .net. Однако есть утечка памяти (в частности, вторая строка firewallRule):

Код: Выделить всё

INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
INetFwRule firewallRule = firewallPolicy.Rules.OfType().Where(x => x.Name == fwRuleName).FirstOrDefault();
Мне приходится перезапускать приложение ежедневно, так как оно расходует столько памяти, сколько я ему позволяю. Я видел его до 12 ГБ, хотя должно быть около 35 МБ. Чтобы достичь такого уровня, требуется всего день или около того. Таким образом, каждый вызов firewallRule съедает ~5–10 МБ. Кажется сумасшедшим, что одна или нулевая запись будет использовать столько памяти.

Я думаю, что это та строка firewallRule, потому что я буквально закомментировал каждую вторую строку в вызываемом методе (и в приложении, если на то пошло), и когда я наконец закомментировал эту строку, утечка прекращается. Пожалуйста, дайте мне знать, если моя логика ошибочна.

Если вы хотите проверить ее, вам нужно сделать ссылку на NetFwTypeLib, чтобы этот код работал.

Кто-нибудь знает, почему это происходит и как это исправить?

Обновление:

Вот исходный код для тех, кто верит, что я еще не все закомментировал:

Код: Выделить всё

public static void FirewallSetup(string ip, string countryCode, bool isIpsString)
{

//    FirewallControl fwCtrl = new FirewallControl();
//    fwCtrl.Block(ip, countryCode, isIpsString);
//}

//private void Block(string ip, string countryCode, bool isIpsString)
//{
var remoteAddresses = "*";
string fwRuleName;
bool createNewFwRule = false;

//var fwRuleSuffix = SQLControl.GetFirewallRuleSuffix(countryCode).ToString();
//if (string.IsNullOrEmpty(fwRuleSuffix) || fwRuleSuffix == "0")
//{
fwRuleName = fwRuleNamePrefix + countryCode;
//}
//else
//{
//    fwRuleName = fwRuleNamePrefix + countryCode + fwRuleSuffix;
//}

INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
INetFwRule firewallRule = firewallPolicy.Rules.OfType().Where(x => x.Name == fwRuleName).FirstOrDefault();

//if (firewallRule == null)
//{
//    createNewFwRule = true;
//}
//else
//{
//    //We need the following for creating the remoteAddresses string below
//    //but, also need to count as Windows has a 5000 ip limit per rule
//    remoteAddresses = firewallRule.RemoteAddresses;
//    string[] aRemoteAddresses = remoteAddresses.Split(",");
//    int remoteAddressesCount = aRemoteAddresses.Length;
//    //Log.Debug(">>>Firewall remote addresses scope=" + remoteAddresses);
//    Log.Warning(">>>" + fwRuleName + " Firewall remote addresses count:" + remoteAddressesCount);

//    //5000 would be 0 to 4999 I think?
//    if (remoteAddressesCount >= 4999)
//    {
//        //If remote ip scope is 5000, create a new fw rule
//        var newFwRuleNameSuffix = SQLControl.GetNewFirewallRuleSuffix(countryCode).ToString();
//        fwRuleName = fwRuleNamePrefix + countryCode + newFwRuleNameSuffix;

//        createNewFwRule = true;
//    }
//}

//If necessary, we create a new rule
//TODO: Create another method for this?
//if (createNewFwRule)
//{
//    firewallRule = (INetFwRule)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule"));
//    firewallRule.Name = fwRuleName;
//    firewallPolicy.Rules.Add(firewallRule);
//    firewallRule.Description = "Block inbound traffic from " + countryCode;
//    firewallRule.Profiles = (int)NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_ALL;
//    firewallRule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
//    firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
//    firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_BLOCK;
//    firewallRule.Enabled = true;
//    //firewallRule.RemoteAddresses = ip;
//    //firewallPolicy.Rules.Add(firewallRule); //throws error and not needed anyway
//    //firewallRule.LocalPorts = "4000";
//    //firewallRule.Grouping = "@firewallapi.dll,-23255";
//    //firewallRule.Profiles = firewallPolicy.CurrentProfileTypes;
//}

//if (isIpsString || remoteAddresses == "*")
//{
//    firewallRule.RemoteAddresses = ip;
//}
//else
//{
//    firewallRule.RemoteAddresses = remoteAddresses + "," + ip;
//}
}
В рабочей среде он просто выполняет этот метод «как есть» и просто съедает память. Опять же, это специфично для .Net Core, поскольку я запускал этот же код в .Net 4.6.1 (без комментариев) более года без проблем.

Теперь, когда я обдумал это и закомментировал, я также могу провести его через некоторый цикл и устранить неполадки здесь внутри компании. Это гонка...

Сервер, на котором он сейчас работает, — Windows Server 2016.

Обновление 2: Оно также воспроизводится в Windows 10. Вот весь код для воспроизведения ошибки:

Код: Выделить всё

using System;
using System.Linq;
using NetFwTypeLib;

namespace FirewallLeakTesterCore
{
class Program
{
static void Main(string[] args)
{
int count = 0;
while (count < 1000)
{
Console.WriteLine(count += 1);
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
INetFwRule firewallRule = firewallPolicy.Rules.OfType().Where(x => x.Name == "firewallRuleName").FirstOrDefault();

}
Console.ReadKey();
}
}
}
И вот результат:

Инструменты диагностики Visual Studio:

Изображение


Похоже на ошибку Microsoft? Думаю, я попробую разобраться с одним из этих профилировщиков памяти, но даже если я обнаружу проблему, что я могу сделать? Это базовый вызов базовой библиотеки Windows, и я думаю, именно поэтому некоторые люди в комментариях упускают из виду суть.

Я не прошу кого-либо профилировать мое приложение в памяти или отслеживать проблему (и никогда не просил... Я уже это делал). Я прошу альтернативные решения. Возможно, есть какая-то проблема со структурой, linq или другое утверждение, которое я мог бы полностью использовать?

Если вы хотите оставить вопрос закрытым, пусть будет так, но мне трудно поверить, что никто больше не столкнется с этим.

Вернуться в «C#»