可能重复:
ConcurrentBag中可能的内存泄漏?
EDIT1:
实际的问题是.你能证实这一点,还是我的样本错了,我错过了一些明显的东西?
我认为ConcurrentBag是一个简单的替代无序列表.但是我错了.ConcurrentBag确实将自己作为ThreadLocal添加到创建线程,这基本上会导致内存泄漏.
class Program
{
static void Main(string[] args)
{
var start = GC.GetTotalMemory(true);
new Program().Start(args);
Console.WriteLine("Diff: {0:N0} bytes", GC.GetTotalMemory(true) - start);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Thread.Sleep(5000);
}
private void Start(string[] args)
{
for (int i = 0; i < 1000; i++)
{
var bag = new ConcurrentBag<byte>();
bag.Add(1);
byte by;
while (bag.TryTake(out by)) ;
}
}
Run Code Online (Sandbox Code Playgroud)
我可以制作Diff 250 KB或100 GB,具体取决于我添加到包中的数据量.数据和包包都消失了.
当我用Windbg打破这个时,我做了一个!DumpHeap -type Concurrent
....
000007ff00046858 1 24 System.Threading.ThreadLocal`1+GenericHolder`3[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System],[System.Threading.ThreadLocal`1+C0[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System]], mscorlib],[System.Threading.ThreadLocal`1+C0[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System]], mscorlib],[System.Threading.ThreadLocal`1+C0[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], …Run Code Online (Sandbox Code Playgroud) 我通过ManualResetEvent创建了一个跨进程事件.当此事件确实发生时,应该取消阻止n个不同进程中的n个线程并开始运行以获取新数据.问题是,似乎ManualResetEvent.Set后跟立即重置不会导致所有等待线程被唤醒.那里的文档很模糊
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
当手动重置事件对象的状态发出信号时,它将保持信号状态,直到它被ResetEvent函数显式重置为无信号.可以在发出对象状态的信号时释放任意数量的等待线程或随后开始对指定事件对象执行等待操作的线程.
有一种名为PulseEvent的方法似乎正是我所需要的,但遗憾的是它也存在缺陷.
等待同步对象的线程可以通过内核模式APC暂时从等待状态中移除,然后在APC完成后返回到等待状态.如果在线程从等待状态中删除期间发生对PulseEvent的调用,则不会释放该线程,因为PulseEvent仅释放那些在被调用时正在等待的线程.因此,PulseEvent不可靠,不应被新应用程序使用.相反,使用条件变量.
现在MS建议使用条件变量.
条件变量是同步原语,它使线程能够等到特定条件发生.条件变量是不能跨进程共享的用户模式对象.
按照文档,我似乎运气不好,可靠地做到了.是否有一种简单的方法可以在没有一个ManualResetEvent的规定限制的情况下完成同样的事情,或者我是否需要为每个侦听器进程创建一个响应事件来为每个订阅的调用者获取ACK?在这种情况下,我需要一个小的共享内存来注册订阅进程的pids,但这似乎带来了自己的一组问题.当一个进程崩溃或没有响应时会发生什么?....
给出一些背景信息.我有新的状态要发布所有其他进程应该从共享内存位置读取.当一次发生多个更新但是进程必须至少读取最后的最新值时,可以错过一次更新.我可以用超时轮询,但这似乎不是一个正确的解决方案.
目前我很感兴趣
ChangeEvent = new EventWaitHandle(false, EventResetMode.ManualReset, counterName + "_Event");
ChangeEvent.Set();
Thread.Sleep(1); // increase odds to release all waiters
ChangeEvent.Reset();
Run Code Online (Sandbox Code Playgroud) 是否在.NET Core工具中发布了VS 2017包含的BinaryFormatter?当我创建.NET Core控制台应用程序时,我找不到BinaryFormatter.有许多Nuget包,但哪一个是正确的,可以使用.NET Core获得一个有效的BinaryFormatter?
顺便说一下,使用已发布的Visual Studio创建一个无法编译的项目有点尴尬.我需要启动我的.NET Core控制台应用程序所在的cmd shell并执行操作
dotnet restore
Run Code Online (Sandbox Code Playgroud)
让它编译.我在参考菜单中错过了VS命令吗?
EDIT1
使用Install-Package BinaryFormatter给了我一个例外
PM> Install-Package BinaryFormatter
Restoring packages for d:\source\vc17\NetCoreApp\ConsoleApp1\ConsoleApp2\ConsoleApp2.csproj...
Install-Package : Package BinaryFormatter 1.0.2 is not compatible with netcoreapp1.1 (.NETCoreApp,Version=v1.1). Package BinaryFormatter 1.0.2 supports:
- dnx451 (DNX,Version=v4.5.1)
- dnxcore50 (DNXCore,Version=v5.0)
At line:1 char:1
+ Install-Package BinaryFormatter
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Install-Package], Exception
+ FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PackageManagement.PowerShellCmdlets.InstallPackageCommand
Install-Package : One or more packages are incompatible with .NETCoreApp,Version=v1.1.
At line:1 char:1
+ Install-Package BinaryFormatter …Run Code Online (Sandbox Code Playgroud) 问题似乎是一个你不应该做的肮脏的黑客,但让我先解释一下.最终目标是在C++中使用方法局部静态.
void Func()
{
static methodLocalObject = new ExpensiveThing();
// use methodlocal Object
}
Run Code Online (Sandbox Code Playgroud)
这与指令指针有什么关系?我想根据我的调用者缓存数据.为了使这个快速,我回到堆栈中以获取我的调用者的地址,并将其用作字典的唯一键来存储数据.这将允许创建一个基于反射的跟踪器,它不会每次都使用Reflection来获取当前方法和类型的名称,但只有一次,并将反射信息存储在哈希表中.
到目前为止,答案仅以单声道为基础.我想尝试一个适用于.NET 3.5/4.0 32/64位的通用解决方案.我知道64位的调用约定是完全不同的,因此获得可靠的东西可能会遇到挑战.但另一方面,我在我的方法中完全控制堆栈的外观.在.NET 3.5和4.0之间,堆栈确实看起来非常不同,当然它在发布版本之间也有所不同.我仍然需要检查NGen是否确实创建了具有不同堆栈布局的代码.一种可能性是使用C++帮助器方法,该方法需要5个魔术整数参数(在x64上只有第5个将在堆栈上)并检查我在堆栈中可以找到它们的位置.另一种可能性是简单地使用整个堆栈,直到我在堆栈上找到我的魔术标记作为键并使用堆栈的这一部分作为唯一足够的密钥.但我不确定这种方法是否可行,或者是否有更好的选择.我知道我可以通过分析或调试apis以安全的方式走栈,但它们都不是很快.
对于跟踪库,通常的方法是使用反射来遍历堆栈以获取当前方法名称和类型.
class Tracer
{
[MethodImpl(MethodImplOptions.NoInlining)]
public Tracer()
{
StackFrame frame = new StackTrace().GetFrame(1); // get caller
Console.WriteLine("Entered method {0}.{1}", frame.GetMethod().DeclaringType.FullName, frame.GetMethod().Name);
}
}
Run Code Online (Sandbox Code Playgroud)
但这很慢.另一个解决方案是直接通过字符串传递数据,速度要快得多,但需要更多的输入.另一种解决方案是使用调用函数的指令指针(如果可以以非常快的方式确定)来绕过昂贵的反射调用.那么这是可能的:
class Tracer
{
static Dictionary<Int64, string> _CachedMethods = new Dictionary<Int64, string>();
[MethodImpl(MethodImplOptions.NoInlining)]
public Tracer()
{
Int64 eip = GetEIpOfParentFrame();
string name;
lock (_CachedMethods)
{
if (!_CachedMethods.TryGetValue(eip, out name))
{
var callingMethod = new StackTrace().GetFrame(1).GetMethod();
name …Run Code Online (Sandbox Code Playgroud) 众所周知,如果您从光盘读取数据,那么您就是IO绑定的,并且您可以比从光盘读取数据更快地处理/解析读取数据.
但这种常识(神话?)并没有反映在我的测试中.当我读取带有double和int的文本文件时,每行以空格分隔,我比物理光盘速度慢得多(因子6).文本文件如下所示
1,1 0
2,1 1
3,1 2
Run Code Online (Sandbox Code Playgroud)
更新 我在一次读取时使用完整缓冲区执行ReadFile时包含了PInvoke性能,以获得"真实"性能.
结果是
Did native read 179,0MB in 0,4s, 484,2MB/s
Did read 10.000.000 lines in 1,6s, 112,7MB/s
Did parse and read unsafe 179,0MB in 2,3s, 76,5MB/s
Did parse and read unsafe char buf 179,0MB in 2,8s, 63,5MB/s
Did read and parse 179,0MB in 9,3s, 19,3MB/s
Run Code Online (Sandbox Code Playgroud)
虽然我确实尝试跳过ParseLinesUnsafeCharBuf中的字符串构造开销,但它仍然比每次分配新字符串的版本慢得多.它仍然比最简单的解决方案的原始20 MB好很多,但我认为.NET应该能够做得更好.如果remoe是解析字符串的逻辑,我确实得到258,8 MB/s,这非常好,接近本机速度.但我没有看到使用不安全代码的方法使我的解析更简单.我必须处理不完整的线条,这使得它非常复杂.
更新 从数字中可以清楚地看出,一个简单的string.split已经花费太多了.但是StringReader也花了不少钱.高度优化的解决方案如何看起来更接近真实的光盘速度?我已经尝试了许多不安全的代码和char缓冲区的方法,但性能提升可能是30%,但我不需要大小的数量级.我可以100MB/s的解析速度.这应该可以通过托管代码实现,还是我错了?
用C#解析的速度是否比我从硬盘读取的速度快?它是Intel …
我有一个简单的方法将数组从一种类型转换为另一种类型.我想找出哪种方法最快.但到目前为止,我得到了不同的结果,我不能断定哪种方法真的更快,哪个边缘.
由于转换仅仅是关于分配内存,读取数组和转换值,我感到惊讶的是值不是更稳定.我想知道如何进行有意义的精确测量,并且不会从一天变为另一天.从一天到另一天,差异大约为20%.
当然,.NET 3.5和4.0的JITer,调试和发布模式之间存在差异,没有在调试器下运行可执行文件(在禁用它之前禁用JIT优化),DEBUG和RELEASE之间的C#编译器代码生成(主要是nop)操作和IL代码中的更多临时变量).
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace PerfTest
{
class Program
{
const int RUNS = 10 * 1000 * 1000;
static void Main(string[] args)
{
int[] array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43 }; …Run Code Online (Sandbox Code Playgroud) 我有一个.il文件,我可以编译没有任何问题.我可以强烈地命名它,所以没有任何问题.但是我无法像我期望的那样通过属性设置文件版本.使用ilasm时如何设置程序集的FileVersion?
如果我往返一次,我总会得到一个.res文件,它只包含不可读的二进制数据.这个res文件里面有什么,可以编辑吗?
代码不起作用
.assembly myAssembly
{
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = { string('1.2.3.4') }
Run Code Online (Sandbox Code Playgroud) 我知道可以自定义TFS 2010构建的构建摘要.但到目前为止,我无法获得如何做到这一点的好信息.有没有人知道自定义VS2010 Build Summary页面的好资源.摘要呈现是通过dll完成的,必须在每台开发人员机器上部署.这不好,但如果没有更好的解决方案,我愿意采取这条路线.
我不是在谈论Web URL,我可以在浏览器中查看构建输出,如果(一如既往)输出变得很大.
.NET是否保证.NET字节数组始终正确对齐?我确实需要这个来处理例如x64中的不安全上下文中的字节数组,以修改具有本机寄存器大小的数据块.
但到目前为止,我还没有找到任何CLR确实给我任何保证我的内存访问正确对齐的文档.
我有一台 Windows 10 机器,其中一些 UI 进程愉快地运行了好几天,直到它在没有任何可见异常的情况下静默退出。我启用了 ETW 跟踪,但几乎所有调用堆栈都提出了 ???? 分数。我想在这个过程中没有发生适当的 ETW 提供程序崩溃。启用进程销毁调用堆栈后,我发现一个
[Root]
ntoskrnl.exe!KiPageFault
ntoskrnl.exe!KiInitiateUserApc
ntoskrnl.exe!KiDeliverApc
ntoskrnl.exe!KiSchedulerApcTerminate
ntoskrnl.exe!PsExitCurrentUserThread
ntoskrnl.exe!PspExitThread
ntoskrnl.exe!PspExitProcess
Run Code Online (Sandbox Code Playgroud)
这是否表示页面错误,所以我应该怀疑硬盘或内存的硬件故障?
我当时发现了一个失败的文件io请求:
The specified request is not a valid operation for the target device.
(0xc0000010) = Event SubType, FSCTL = Event Type, C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel\v4.0_4.0.0.0__b77a5c561934e089\System.ServiceModel.dll
Run Code Online (Sandbox Code Playgroud)
这让我觉得硬盘有问题。