什么会导致内存泄漏(或不断增加)?共享内存DLL+;c#应用程序

什么会导致内存泄漏(或不断增加)?共享内存DLL+;c#应用程序,c#,c++,c,C#,C++,C,我有一个简单的共享内存DLL,用于从非托管应用程序到托管应用程序的进程间数据交换。 我注意到我的托管应用程序内存在稳步增长。 有人能告诉我原因是什么,如何找到它,如何修复它吗? 以下代码的相关部分 cpp SharedMem.DLL: #pragma data_seg( ".IPC" ) .... double darr[MAXITEMS] = { 0.0 } ; .... #pragma data_seg() .... double __stdcall MGetDouble (int idx

我有一个简单的共享内存DLL,用于从非托管应用程序到托管应用程序的进程间数据交换。 我注意到我的托管应用程序内存在稳步增长。 有人能告诉我原因是什么,如何找到它,如何修复它吗? 以下代码的相关部分

cpp SharedMem.DLL:

#pragma data_seg( ".IPC" )
....
double darr[MAXITEMS] = { 0.0 } ; 
....
#pragma data_seg()
....
double __stdcall MGetDouble (int idx)
{
    if ( idx>= 0 && idx < MAXITEMS)
    {
        return darr[idx]; 
    }
    else
    {
        return -1.0 ; 
    }
}

int __stdcall MSetDouble (int idx, double dvalue)
{
    if ( idx>= 0 && idx< MAXITEMS)
    {
        darr[idx] = dvalue;
        return idx;
    }
    else
    {
        return -1;
    }
}
#pragma数据段(“.IPC”)
....
双darr[MAXITEMS]={0.0};
....
#pragma data_seg()
....
double uu stdcall MGetDouble(int idx)
{
如果(idx>=0&&idx=0&&idx
和c#应用程序:

[DllImport(“SharedMem.DLL”,CallingConvention=CallingConvention.StdCall)]
公共静态外部双MGetDouble(int索引);
....
私有无效计时器1_刻度(对象发送方,事件参数e)
{
ThreadPool.QueueUserWorkItem(dosmth);
}
public object lockobj=新对象();
公共无效文件(对象o)
{
if(监视器TryEnter(锁定对象,50))
{
....
double[,]矩阵=新的double[大小,TSIZE];
....
双gvd;
int k;
对于(int i=0;i
QueueUserWorkItem将在线程池(TP)上运行您的方法-如果以前的请求尚未完成,则新请求将阻止TP线程。一段时间后,如果TP在空闲线程上运行不足,它将开始创建更多线程,每个线程至少消耗1MB的堆栈

如果对您的应用程序有意义,您可能希望在前一个请求完成后运行新请求(例如,运行计时器,使其执行一次,然后使用计时器。更改为在处理完成后安排下一个执行时间)

您还可以使用,并使用DumpHeap/HeapStat等命令检查根目录,以查看内存的确切位置。

尝试以下方法:

public class doSmthClass()
{
    public void doSmthfromClass(...
}
并改变你的“外在”行为:


它长了多少?它会在某个时候停止吗?您是否尝试过进行挂起转储以查看是什么原因导致内存使用量的增加?每小时增长约2000万次。当我从内存异常中退出时,当应用程序的大小达到大约800m(Windows7 64位,4GB内存)时,我注意到了这一点。当不使用MGetDouble()时,它不会增长。我尝试使用windbg和sos.dll进行调试,但是,由于我在这方面经验不足,无法找到任何东西。你能给我介绍一些关于处理这类问题的好文章吗?与执行dosmth()所用的时间相比,timer1的周期是多少?ThreadPool.GetAvailableThreads是否在稳步下降?您还应该只在TryEnter成功时调用Monitor.Exit。我尝试了不使用threadpool,只调用dosmth(),但问题仍然存在。我还花了一些时间处理windbg/sos,无法找到增长的内容。最大的大小有System.String和System.Double[,](在我的代码中是矩阵[,]),但它们没有稳定增长。@NickBilak-即使不直接调用线程池,问题也会存在-计时器回调在TP工作线程上执行。执行可能仍然重叠(可以在前一个执行完成之前开始)。我已经了解到Windows.Forms.Timer是在主UI线程上执行的,而不是在TP上执行的。这是错的吗?我还尝试了System.Timers.Timer(mTimer.Enabled=false;.do smth..mTimer.Enabled=true;),从而确保只有一个实例正在运行。此外,还有一个用于相同目的的锁。我不知道它是winforms应用程序。那么您根本不需要同步(锁)。在这种情况下,如果UI线程不能以计时器周期性启动的速度处理请求,那么它的队列可能会被请求阻塞。我怀疑这些请求可能会导致如此严重的内存泄漏(这仍然取决于计时器的频率)。在实际代码中,这有点类似(我简化了问题代码),除了myInstance始终保持活动状态,我无法更改这一点。如果myInstance保持活动状态,并且从未被处理,则您的问题位于未正确处理的代码的未管理区域内。看起来是这样的,因为没有调用MgetDouble(),并且通过使用随机数据填充矩阵[,],就不会增长。但是怎么做呢?内存(darr)在DLL中分配一次并保持不变,dosmth()从MgetDouble()读取几乎相同的索引。为什么垃圾收集器不能释放本地var矩阵[,]的内存?我想我需要花更多的时间在windbg/So上,我会考虑如何重新设计并应用您的建议,然后尝试链接到一个托管dll,它什么都不做——看看您在内存方面是否有相同的行为。我的意思是,您可以将焦点从查找链接dll上的行更改为更全局的视图,以确保问题不在链接本身。如果您遇到一些相同的问题-您的问题与.NET链接dll的方式有关,如果不是-则是非托管代码。
public class doSmthClass()
{
    public void doSmthfromClass(...
}
public void dosmth(object o)
{
  :
  var myInstance = new doSmthClass();
  myInstance.doSmthFromClass();
  :
}