微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

这个简单的网络核心 Api 中的享元模式使用更多内存 ram

如何解决这个简单的网络核心 Api 中的享元模式使用更多内存 ram

我正在尝试在一个简单的 .net 核心 Api 中复制享元方法模式,以查看与不使用该模式相比节省了多少内存。

我有两种方法,第一种方法不使用模式创建 5000 个对象,另一种方法使用模式创建 5000 个对象。在他们每个人创建对象后,然后他们调用一个方法来返回应用程序使用的当前内存。

public class MemoryService : IMemoryService
{
    private readonly TreeFactory _treeFactory;
    public MemoryService()
    {
        _treeFactory = new TreeFactory();
    }

    //create without pattern
    public long SetobjectsMemory()
    {
        List<Tree> trees = new List<Tree>();
        for (int i = 0; i < 5000; i++)
        {
            var tree = new Tree()
            {
                Id = new Random().Next(1,9999999),Part = new PartTree()
                {
                    Name = "Nameany",Bark = "Barkany",Color = "Colorany"
                }
            };
            trees.Add(tree);
        };

        return Utilities.GetCurrentMemoryUsed();
    }

    //crete with flyweight pattern
    public long SetobjectsMemoryFactory()
    {
        List<Tree> trees = new List<Tree>();
        for (int i = 0; i < 5000; i++)
        {
            var tree = new Tree()
            {
                Id = new Random().Next(1,Part = _treeFactory.GetPartTree("Nameany","Barkany","Colorany")
            };
            trees.Add(tree);
        }

        return Utilities.GetCurrentMemoryUsed();
    }
}

我使用这种模式就像一个使用部件列表的类,如果存在则返回一个部件对象。

public class TreeFactory
{
    private static List<PartTree> _parts;

    public TreeFactory() {
        _parts = new List<PartTree>();
    }
    public PartTree GetPartTree(string name,string bark,string color)
    {
        if (_parts.Any(x => x.Name == name && x.Bark == bark && x.Color == color))
        {
            return _parts.Where(x => x.Name == name && x.Bark == bark && x.Color == color).FirstOrDefault();
        }
        else {
            var newpart = new PartTree()
            {
                Name = name,Bark = bark,Color = color
            };
            _parts.Add(newpart);
            return newpart;
        }
        
    }
}

获取App当前使用内存的方式是使用Process这种方式(在Utilities类中):

public static long GetCurrentMemoryUsed() {
        Int64 memory;
        using (Process proc = Process.GetCurrentProcess())
        {
            memory = proc.PrivateMemorySize64 / (1024 * 1024);
        }

        return memory;
    }

在我的 Startup 中,我像单例一样注入 MemoryService。在控制器中,我使用 3 种方法调用函数

 [HttpGet,Route(nameof(WeatherForecastController.GenerateMemory))]
    public IActionResult GenerateMemory()
    {
        var total=_memoryService.SetobjectsMemory();
        return Ok(total);
    }

    [HttpGet,Route(nameof(WeatherForecastController.GenerateLiftMemory))]
    public IActionResult GenerateLiftMemory()
    {
        var total = _memoryService.SetobjectsMemoryFactory();
        return Ok(total);
    }

    [HttpGet,Route(nameof(WeatherForecastController.GetMemory))]
    public IActionResult GetMemory()
    {
        var total = Utilities.GetCurrentMemoryUsed();
        return Ok(total);
    }

问题是:当我在导航器中调用控制器中的方法无模式(/weatherforecast/GenerateMemory),然后返回(current)+2mb,但是当我调用方法使用模式 (/weatherforecast/GenerateLiftMemory) 返回(current)+3mb

为什么有模式享元的方法比没有模式的方法返回更多使用的MB(增长)??

带有用于测试的代码的存储库。 Gitlab repository memory api

解决方法

使用 TreeFactory 的代码消耗更多内存,因为它的 GetPartTree 方法在循环中被多次调用,因此其中的 Linq 方法 AnyWhere .这两种方法都会在后台创建额外的 Iterator 对象,以便遍历集合并导致额外的内存消耗。

我使用 BenchmarkDotNet 编写了简单的基准测试,并提供了更多选项来演示该问题

扩展内存服务

public class MemoryService : IMemoryService
{
    private const int TreeCount = 50000;
    private readonly TreeFactory _treeFactory;
    public MemoryService()
    {
        _treeFactory = new TreeFactory();
    }

    //crea objetos en memoria sin patrones
    public decimal SetObjectsMemory()
    {
        List<Tree> trees = new List<Tree>();
        for (int i = 0; i < TreeCount; i++)
        {
            var tree = new Tree()
            {
                Id = 1,Part = new PartTree()
                {
                    Name = "Nameany",Bark = "Barkany",Color = "Colorany"
                }
            };
            trees.Add(tree);
        };

        return Utilities.GetCurrentMemoryUsed();
    }

    //crea objetos en memoria usando patron flyweight
    public decimal SetObjectsMemoryFactory()
    {
        List<Tree> trees = new List<Tree>();
        for (int i = 0; i < TreeCount; i++)
        {
            var tree = new Tree()
            {
                Id = 1,Part = _treeFactory.GetPartTree("Nameany","Barkany","Colorany")
            };
            trees.Add(tree);
        }

        return Utilities.GetCurrentMemoryUsed();
    }

    public decimal SetObjectsMemoryFactoryImproved()
    {
        List<Tree> trees = new List<Tree>();
        for (int i = 0; i < TreeCount; i++)
        {
            var tree = new Tree()
            {
                Id = 1,Part = _treeFactory.GetPartTreeImproved("Nameany","Colorany")
            };
            trees.Add(tree);
        }

        return Utilities.GetCurrentMemoryUsed();
    }

    //crea objetos en memoria usando patron flyweight
    public decimal SetObjectsMemoryFactoryWithoutLambda()
    {
        List<Tree> trees = new List<Tree>();
        for (int i = 0; i < TreeCount; i++)
        {
            var tree = new Tree()
            {
                Id = 1,Part = _treeFactory.GetPartTreeWithoutLambda("Nameany","Colorany")
            };
            trees.Add(tree);
        }

        return Utilities.GetCurrentMemoryUsed();
    }
}

扩展树工厂

public class TreeFactory
{
    private static List<PartTree> _parts;

    public TreeFactory()
    {
        _parts = new List<PartTree>();
    }

    public PartTree GetPartTree(string name,string bark,string color)
    {
        if (_parts.Any(x => x.Name == name && x.Bark == bark && x.Color == color))
        {
            return _parts.Where(x => x.Name == name && x.Bark == bark && x.Color == color).FirstOrDefault();
        }

        var newpart = new PartTree()
        {
            Name = name,Bark = bark,Color = color
        };
        _parts.Add(newpart);
        return newpart;
    }

    public PartTree GetPartTreeImproved(string name,string color)
    {
        var existingPart = _parts.Where(x => x.Name == name && x.Bark == bark && x.Color == color).FirstOrDefault();
        if (existingPart != null)
            return existingPart;

        var newpart = new PartTree()
        {
            Name = name,Color = color
        };
        _parts.Add(newpart);
        return newpart;

    }

    public PartTree GetPartTreeWithoutLambda(string name,string color)
    {
        for (int i = 0; i < _parts.Count; i++)
        {
            var x = _parts[i];
            if (x.Name == name && x.Bark == bark && x.Color == color)
                return x;
        }

        var newpart = new PartTree()
        {
            Name = name,Color = color
        };
        _parts.Add(newpart);
        return newpart;

    }
}

在单独的控制台项目中进行基准测试

class Program
{
    static void Main(string[] args)
    {
        var result = BenchmarkRunner.Run<MemoryBenchmark>();
    }
}


[MemoryDiagnoser]
public class MemoryBenchmark
{
    private IMemoryService memoryService;

    [GlobalSetup]
    public void Setup()
    {
        memoryService = new MemoryService();
    }

    [Benchmark]
    public object SimpleTrees()
    {
        var trees = memoryService.SetObjectsMemory();
        return trees;
    }

    [Benchmark]
    public object FlyTrees()
    {
        var trees = memoryService.SetObjectsMemoryFactory();
        return trees;
    }

    [Benchmark]
    public object FlyTreesImproved()
    {
        var trees = memoryService.SetObjectsMemoryFactoryImproved();
        return trees;
    }

    [Benchmark]
    public object FlyTreesWithoutLambda()
    {
        var trees = memoryService.SetObjectsMemoryFactoryWithoutLambda();
        return trees;
    }
}

及其结果

方法 平均 错误 StdDev Gen 0 Gen 1 第 2 代 已分配
简单树 9.040 毫秒 0.1804 毫秒 0.2346 毫秒 718.7500 453.1250 265.6250 4.44 MB
飞树 19.701 毫秒 0.1716 毫秒 0.1521 毫秒 2500.0000 906.2500 437.5000 15.88 MB
FlyTreesImproved 18.075 毫秒 0.2869 毫秒 0.2684 毫秒 1781.2500 625.0000 312.5000 10.92 MB
FlyTreesWithoutLambda 4.919 毫秒 0.0273 毫秒 0.0242 毫秒 421.8750 281.2500 281.2500 2.53 MB

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。