Multithreading .net内核上ProtoBuf序列化的内存泄漏
我正试图找出protobuf序列化的.net核心应用程序出现问题的原因,所以我编写了一个测试应用程序并。。。有一些奇怪的问题。如果我使用任务,就会有内存泄漏;如果我使用线程,就不会有内存泄漏 任务示例:Multithreading .net内核上ProtoBuf序列化的内存泄漏,multithreading,memory-leaks,asp.net-core,protocol-buffers,protobuf-net,Multithreading,Memory Leaks,Asp.net Core,Protocol Buffers,Protobuf Net,我正试图找出protobuf序列化的.net核心应用程序出现问题的原因,所以我编写了一个测试应用程序并。。。有一些奇怪的问题。如果我使用任务,就会有内存泄漏;如果我使用线程,就不会有内存泄漏 任务示例: internal class Program { private static void Main(string[] args) { var data = new Person { Id = 1, N
internal class Program
{
private static void Main(string[] args)
{
var data = new Person
{
Id = 1,
Name = new string('q', 10000),
Address = new Address
{
Line1 = new string('w', 10000),
Line2 = new string('e', 10000)
}
};
//for (var i = 0; i < 100; i++)
//{
// var thread = new Thread(() =>
// {
// while (true)
// try
// {
// var b = ProtoSerialize(data);
// Person serializedPerson;
// using (Stream stream2 = new MemoryStream(b))
// {
// serializedPerson = Serializer.Deserialize<Person>(stream2);
// }
// }
// catch (Exception e)
// {
// Console.WriteLine(e);
// }
// });
// thread.Start();
//}
for (var i = 0; i < 100; i++)
{
new Task(() =>
{
while (true)
{
var b = ProtoSerialize(data);
Person serializedPerson;
using (Stream stream2 = new MemoryStream(b))
{
serializedPerson = Serializer.Deserialize<Person>(stream2);
}
}
}).Start();
}
Console.ReadLine();
}
public static byte[] ProtoSerialize<T>(T record) where T : class
{
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, record);
return stream.ToArray();
}
}
}
[ProtoContract]
public class Person
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
[ProtoContract]
public class Address
{
[ProtoMember(1)]
public string Line1 { get; set; }
[ProtoMember(2)]
public string Line2 { get; set; }
}
内部类程序
{
私有静态void Main(字符串[]args)
{
var数据=新人
{
Id=1,
名称=新字符串('q',10000),
地址=新地址
{
第1行=新字符串('w',10000),
第2行=新字符串('e',10000)
}
};
//对于(变量i=0;i<100;i++)
//{
//变量线程=新线程(()=>
// {
//while(true)
//试一试
// {
//var b=原型序列化(数据);
//人与人;
//使用(stream2=新内存流(b))
// {
//serializedPerson=Serializer.Deserialize(stream2);
// }
// }
//捕获(例外e)
// {
//控制台写入线(e);
// }
// });
//thread.Start();
//}
对于(变量i=0;i<100;i++)
{
新任务(()=>
{
while(true)
{
var b=原型序列化(数据);
人与人;
使用(stream2=新内存流(b))
{
serializedPerson=Serializer.Deserialize(stream2);
}
}
}).Start();
}
Console.ReadLine();
}
公共静态字节[]原型序列化(T记录),其中T:class
{
使用(var stream=new MemoryStream())
{
序列化器。序列化(流、记录);
返回流ToArray();
}
}
}
[原始合同]
公共阶层人士
{
[原成员(1)]
公共int Id{get;set;}
[原成员(2)]
公共字符串名称{get;set;}
[原成员(3)]
公共广播地址{get;set;}
}
[原始合同]
公共课堂演讲
{
[原成员(1)]
公共字符串Line1{get;set;}
[原成员(2)]
公共字符串第2行{get;set;}
}
以及dotMemory的屏幕截图:
因此,如果我使用线程(注释代码)
for(变量i=0;i<100;i++)
{
变量线程=新线程(()=>
{
while(true)
尝试
{
var b=原型序列化(数据);
人与人;
使用(stream2=新内存流(b))
{
serializedPerson=Serializer.Deserialize(stream2);
}
}
捕获(例外e)
{
控制台写入线(e);
}
});
thread.Start();
}
那么就没有泄漏:
因此,问题是:
UPD1:在主线程中调用GC.Collect不会更改任何内容(仍然存在内存泄漏)这很有趣。protobuf net对一些后台池的使用是有限的,例如,
ProtoReader
有一个[ThreadStatic]
实例,尽管它本身是一个轻型对象;虽然它确实保留了一个byte[]
池,但是[ThreadStatic]
实例并没有引用该池(在此之前缓冲区被释放到池中)。因此,没有什么东西会立即浮现在脑海中;您是否尝试过执行一些强制的GC.Collect
s以查看是否有任何泄漏,而不是根本没有收集?您是否尝试过用虚拟代码(例如Thread.Sleep(100);
)替换所有protobuf网络,以查看您是否只是看到了TPL机器的重量?您知道(从该工具)哪些对象类型导致了开销吗
也有可能这仅仅是线程使用非常不同的结果,这会扰乱
GC
:任务
代码将使用线程池
,因此线程数量有限。这既不是好的,也不是坏的,只是:不同。打开快照比较,打开“新”对象,看看这些对象是什么以及它们为什么保存在内存中。使用内存探查器电源。注意:昨天出现了一个新的构建,它解决了一个非常特定的内存场景-不确定这是否相关,但您可能想尝试一下itI。我遇到了完全相同的问题,正在处理大对象,并使用dotmemory,这是在Serializer类上发现的
for (var i = 0; i < 100; i++)
{
var thread = new Thread(() =>
{
while (true)
try
{
var b = ProtoSerialize(data);
Person serializedPerson;
using (Stream stream2 = new MemoryStream(b))
{
serializedPerson = Serializer.Deserialize<Person>(stream2);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
});
thread.Start();
}