Castle Windsor 解决的依赖项比使用 SignalR Activator 发布的依赖项多

发布于 2025-01-13 23:08:09 字数 3218 浏览 0 评论 0原文

不知道我的分析是否正确。但我遇到了 castle 和 SignalR 的内存泄漏问题。对于瞬态注册组件来说,这是一个众所周知的“问题”,例如(SignalR服务器内存消耗(温莎IHubActivator是罪魁祸首?) / https://github.com/SignalR/SignalR/issues/3208 以及很多其他的)。

我正在使用这个 SignalR 激活器:


public class SignalRHubActivator : IHubActivator
    {
        private readonly IWindsorContainer _container;

        public SignalRHubActivator(IWindsorContainer container)
        {
            _container = container ?? throw new ArgumentNullException("container");
        }

        private int GetTrackedComponentsCount()
        {
            var host = (IDiagnosticsHost)ContainerManager.Container.Kernel.GetSubSystem(SubSystemConstants.DiagnosticsKey);
            var diagnostics = host.GetDiagnostic<ITrackedComponentsDiagnostic>();
            var inspect = diagnostics.Inspect();
            var all = inspect
                .Select(x => new { Name = x.Key.ComponentModel.ToString(), Count = x.Count() }).ToList();
            return all.Sum(x => x.Count);
        }
        public IHub Create(HubDescriptor descriptor)
        {
            var logger = _container.Resolve<ILogger>();

            var beforeResolvingCount = GetTrackedComponentsCount();
            logger.Info($"BEFORE Resolving - In SignalR Activator. Components waiting to release : {beforeResolvingCount}");
            
            var instance = _container.Resolve(descriptor.HubType) as IHub;
            var beforeReleasingCount = GetTrackedComponentsCount();
            logger.Info($"Before Releasing  - In SignalR Activator. Components waiting to release : {beforeReleasingCount} |  Difference {beforeResolvingCount - beforeReleasingCount}");

            _container.Release(instance);

            var afterReleasingCount = GetTrackedComponentsCount();
            logger.Info($"After Releasing  - In SignalR Activator. Components waiting to release : {afterReleasingCount} | Difference {beforeReleasingCount - afterReleasingCount}");
            return instance;
        }
    }

您可以看到我添加了一些日志来查看要发布的跟踪组件的数量。正如您可能知道的,castle 的默认发布策略会跟踪需要发布的瞬态组件(出于某种原因)。它可以防止它们被垃圾收集器收集。我的集线器被注册为瞬态,因此当我解析集线器时,Castle 容器应该跟踪它们。事情就是这样,你可以看到我添加了 3 个日志。每次我记录温莎城堡跟踪组件的数量。

  • 第一次它给我记录 0,因为当时没有解决任何问题。
  • 对于第二个日志,我们可以看到该数字发生了变化,在我的例子中是 456(这是我知道的很多)
  • 第三次,它应该是 0,因为我释放了集线器...但由于某种原因我不知道我不知道它打印的是 436...所以只有 20 个组件从跟踪组件中删除...即使我释放了条目对象...

有谁知道为什么我有这种奇怪的行为?为什么温莎城堡仍然跟踪我的 Hub 的依赖项?

我查看了Castle Windsor的代码,我们可以看到,当一个组件被释放时,该组件的依赖项也会被释放:

https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/MicroKernel/Burden.cs#L132

当然我们可以在日志中看到它发布了超过一个组件......所以它实际上释放了一些依赖项,但不是全部。为什么 ?

感谢您阅读我!我希望我能获得有关该问题或误解的更多信息。

编辑:问题不在于温莎城堡发布功能。问题是我正在使用旧包中的 HybridPerWebRequestTransient() 方法注册我的集线器的依赖项。这与将它们注册为 Transient 并不完全相同。

I don't know if my analyse is correct or not. But i'm facing some memory leak with castle and SignalR. It's a well known "issue" for Transient registered components see for example (SignalR server memory consumption (Windsor IHubActivator to blame?) / https://github.com/SignalR/SignalR/issues/3208 and a lot of others).

I'm using this SignalR activator :


public class SignalRHubActivator : IHubActivator
    {
        private readonly IWindsorContainer _container;

        public SignalRHubActivator(IWindsorContainer container)
        {
            _container = container ?? throw new ArgumentNullException("container");
        }

        private int GetTrackedComponentsCount()
        {
            var host = (IDiagnosticsHost)ContainerManager.Container.Kernel.GetSubSystem(SubSystemConstants.DiagnosticsKey);
            var diagnostics = host.GetDiagnostic<ITrackedComponentsDiagnostic>();
            var inspect = diagnostics.Inspect();
            var all = inspect
                .Select(x => new { Name = x.Key.ComponentModel.ToString(), Count = x.Count() }).ToList();
            return all.Sum(x => x.Count);
        }
        public IHub Create(HubDescriptor descriptor)
        {
            var logger = _container.Resolve<ILogger>();

            var beforeResolvingCount = GetTrackedComponentsCount();
            logger.Info(
quot;BEFORE Resolving - In SignalR Activator. Components waiting to release : {beforeResolvingCount}");
            
            var instance = _container.Resolve(descriptor.HubType) as IHub;
            var beforeReleasingCount = GetTrackedComponentsCount();
            logger.Info(
quot;Before Releasing  - In SignalR Activator. Components waiting to release : {beforeReleasingCount} |  Difference {beforeResolvingCount - beforeReleasingCount}");

            _container.Release(instance);

            var afterReleasingCount = GetTrackedComponentsCount();
            logger.Info(
quot;After Releasing  - In SignalR Activator. Components waiting to release : {afterReleasingCount} | Difference {beforeReleasingCount - afterReleasingCount}");
            return instance;
        }
    }

You can see that I have added some logs to see the number of tracked components to be released. AS you may know castle with its default Release Policy keep tracks of Transient components that needs to be released (for some reason). And it prevents them to be collected by the Garbage collector. My hubs are registered to be Transient, so Castle container should keep track them when I resolve a Hub. And that's what happen, you can see that i add 3 logs. Each time i log the number of Castle Windsor Tracked Components.

  • For the first time it logs me 0 because nothing has been resolve at that time.
  • For the second log, we can see that that number changes, in my case 456 (that's a lot I know)
  • For the third time, it should be 0 because, i released the hub... But for some reason that i don't know it's printed 436... So only 20 components are removed from tracked components... Even i release the entry object ...

Does anyone have any idea why i have this strange behaviour ? Why Castle Windsor still keep track of the dependencies of my Hub?

I checked in the Castle Windsor code and we can see that when an component is released, the dependencies of that component are also released :

https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/MicroKernel/Burden.cs#L132

And of course we can see in the logs that it releases more than one component... So it actually releasing some dependencies but not all. Why ?

Thank you for reading me ! I hope i can have more info about the issue or the misunderstanding.

Edit : The problem wasn't Castle Windsor releasing feature. The problem was that i was registering the dependencies of my Hub using HybridPerWebRequestTransient() method from a old package. Which is not totally the same as registering them as Transient.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文