这个简单的网络核心 Api 中的享元模式使用了更多的内存 ram
Flyweight pattern in this simple net core Api uses more memory ram
我正在尝试在一个简单的 .net 核心中应用 Flyweight 方法模式 Api 以查看与不使用该模式相比节省了多少内存。
我有两种方法,第一种不使用模式创建 5000 个对象,另一种使用模式创建 5000 个对象。在他们每个人创建对象之后,然后他们调用一个方法,该方法return是应用程序使用的当前内存。
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, 9999999),
Part = _treeFactory.GetPartTree("Nameany", "Barkany", "Colorany")
};
trees.Add(tree);
}
return Utilities.GetCurrentMemoryUsed();
}
}
我使用类似 class 的模式,它使用部件列表和 return 部件对象(如果存在)。
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中class):
public static long GetCurrentMemoryUsed() {
Int64 memory;
using (Process proc = Process.GetCurrentProcess())
{
memory = proc.PrivateMemorySize64 / (1024 * 1024);
}
return memory;
}
在我的 Startup 中,我像 Singleton 一样注入 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),然后这个 returns (current)+2mb,但是当我调用该方法时
with pattern (/weatherforecast/GenerateLiftMemory) this returns (current)+3mb.
为什么有模式享元 returns 的方法比没有模式的方法使用更多的 MB(增长)??
包含测试代码的存储库。 Gitlab repository memory api
使用 TreeFactory
的代码消耗更多内存,因为它的 GetPartTree
方法在循环中被多次调用,例如 Linq
方法 Any
和 Where
在里面。这两种方法都会在后台创建额外的 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", "Barkany", "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", "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();
}
var newpart = new PartTree()
{
Name = name,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
public PartTree GetPartTreeImproved(string name, string bark, 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,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
public PartTree GetPartTreeWithoutLambda(string name, string bark, 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,
Bark = bark,
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;
}
}
及其结果
Method
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
SimpleTrees
9.040 ms
0.1804 ms
0.2346 ms
718.7500
453.1250
265.6250
4.44 MB
FlyTrees
19.701 ms
0.1716 ms
0.1521 ms
2500.0000
906.2500
437.5000
15.88 MB
FlyTreesImproved
18.075 ms
0.2869 ms
0.2684 ms
1781.2500
625.0000
312.5000
10.92 MB
FlyTreesWithoutLambda
4.919 ms
0.0273 ms
0.0242 ms
421.8750
281.2500
281.2500
2.53 MB
我正在尝试在一个简单的 .net 核心中应用 Flyweight 方法模式 Api 以查看与不使用该模式相比节省了多少内存。
我有两种方法,第一种不使用模式创建 5000 个对象,另一种使用模式创建 5000 个对象。在他们每个人创建对象之后,然后他们调用一个方法,该方法return是应用程序使用的当前内存。
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, 9999999),
Part = _treeFactory.GetPartTree("Nameany", "Barkany", "Colorany")
};
trees.Add(tree);
}
return Utilities.GetCurrentMemoryUsed();
}
}
我使用类似 class 的模式,它使用部件列表和 return 部件对象(如果存在)。
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中class):
public static long GetCurrentMemoryUsed() {
Int64 memory;
using (Process proc = Process.GetCurrentProcess())
{
memory = proc.PrivateMemorySize64 / (1024 * 1024);
}
return memory;
}
在我的 Startup 中,我像 Singleton 一样注入 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),然后这个 returns (current)+2mb,但是当我调用该方法时 with pattern (/weatherforecast/GenerateLiftMemory) this returns (current)+3mb.
为什么有模式享元 returns 的方法比没有模式的方法使用更多的 MB(增长)??
包含测试代码的存储库。 Gitlab repository memory api
使用 TreeFactory
的代码消耗更多内存,因为它的 GetPartTree
方法在循环中被多次调用,例如 Linq
方法 Any
和 Where
在里面。这两种方法都会在后台创建额外的 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", "Barkany", "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", "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();
}
var newpart = new PartTree()
{
Name = name,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
public PartTree GetPartTreeImproved(string name, string bark, 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,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
public PartTree GetPartTreeWithoutLambda(string name, string bark, 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,
Bark = bark,
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;
}
}
及其结果
Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|
SimpleTrees | 9.040 ms | 0.1804 ms | 0.2346 ms | 718.7500 | 453.1250 | 265.6250 | 4.44 MB |
FlyTrees | 19.701 ms | 0.1716 ms | 0.1521 ms | 2500.0000 | 906.2500 | 437.5000 | 15.88 MB |
FlyTreesImproved | 18.075 ms | 0.2869 ms | 0.2684 ms | 1781.2500 | 625.0000 | 312.5000 | 10.92 MB |
FlyTreesWithoutLambda | 4.919 ms | 0.0273 ms | 0.0242 ms | 421.8750 | 281.2500 | 281.2500 | 2.53 MB |