几个月前,一名同事提到我,我们内部的Delphi应用程序似乎占用了8 GB的RAM。我告诉他了:

That’s not possible

32位应用程序仅具有32位虚拟地址空间。即使有内存泄漏,它可能消耗的大多数内存是2 GB。之后,分配将失败(因为虚拟地址空间中不会有空格)。而在内存泄漏的情况下,虚拟页面将被换出到页面文件,释放物理RAM。

但他指出,Windows资源监视器表示系统上可用的RAM不足1 GB。而我们的应用程序只使用220 MB的虚拟内存:关闭它释放了8 GB的物理RAM。

所以我测试了

我让应用程序运行了几个星期,今天我终于决定测试了。

首先我关闭应用程序之前看内存使用情况:

>工作集(RAM)为241 MB
>使用的总虚拟内存:409 MB

我使用资源监视器来检查应用程序使用的内存和正在使用的总RAM:

>应用程序分配的虚拟内存:252 MB
>正在使用的物理内存:14 GB

然后关闭应用程序后的内存使用:

>使用物理内存:6.6 GB(较低7.4 GB)

我还使用Process Explorer查看之前和之后的物理RAM使用情况。唯一的区别是8 GB的RAM真的没有提交,现在免费:

| Item                          | Before     | After     |
|-------------------------------|------------|-----------|
| Commit Charge (K)             | 15,516,388 | 7,264,420 |
| Physical Memory Available (K) |  1,959,480 | 9,990,012 |
| Zeroed Paging List  (K)       |    539,212 | 8,556,340 |

注意:有趣的是,Windows会浪费时间立即清除所有内存,而不是简单地将其放在备用列表中,并根据需要将其清零(因为内存请求需要满足)。

这些东西都没有解释RAM是什么(你在做什么只是坐在那里!你包含什么??)

那是什么记忆!

该RAM必须包含有用的东西;它必须有一些目的。为此,我转向SysInternals的RAMMap。它可能会破坏内存分配。

RAMMap提供的唯一线索是,8 GB的物理内存与称为“会话私有”的内容相关联。这些会话私人分配不与任何进程相关联(即不是我的进程):

| Item                   | Before   | After    |
|------------------------|----------|----------|
| Session Private        | 8,031 MB |   276 MB |
| Unused                 | 1,111 MB | 8,342 MB |

我当然没有在EMS,xms,AWE等方面做任何事情

在32位非管理员应用程序中可能会发生什么,导致Windows分配额外的7 GB RAM?

>这不是一个交换项目的缓存
>它不是SuperFetch缓存

就在那里消耗RAM。

会话私人

关于“会话私人”内存的唯一信息是a blog post announcing RAMMap:

Session Private: Memory that is private to a particular logged in session. This will be higher on RDS Session Host servers.

这是什么样的应用程序

这是一个32位的本机Windows应用程序(即不是Java而不是.NET)。因为它是一个本机的Windows应用程序,当然,大量使用Windows API。

应该指出的是,我并没有要求人们调试应用程序;我希望Windows开发人员知道为什么Windows可能会保留我从未分配的内存。话虽如此,最近才发生的(最近2年或3年)的唯一改变是每5分钟一次屏幕截图,并将其保存到用户的%LocalAppData%文件夹。定时器每五分钟触发一次:

QueueUserWorkItem(TakeScreenshotthreadProc);

和伪代码的线程方法:

void TakeScreenshotthreadProc(Pointer data)
{
   String szFolder = GetFolderPath(CSIDL_LOCAL_APPDTA);
   ForceDirectoryExists(szFolder);

   String szFile = szFolder + "\" + FormatDateTime('yyyyMMdd"_"hhnnss',Now()) + ".jpg";

   Image destimage = new Image();
   try
   {
      CaptureDesktop(destimage);

      JPEGImage jpg = new JPEGImage();
      jpg.copyFrom(destimage); 
      jpg.CompressionQuality = 13;
      jpg.Compress();

      HANDLE hFile = CreateFile(szFile,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,null,CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_ENCRYPTED,0);
      //error checking elucidated
      try
      {
          Stream stm = new HandleStream(hFile);
          try
          {
             jpg.SavetoStream(stm);
          }
          finally
          {
             stm.Free();
          }
       }
       finally
       {
          CloseHandle(hFile);
       }
    }
    finally
    {
       destimage.Free();
    }
}
很可能在你的应用程序的某个地方你正在分配系统资源,而不是释放它们。任何创建对象并返回句柄的WinApi调用可能是可疑的。例如(在有限内存的系统上小心运行) – 如果您没有6GB的空间,那么它的页面将会很差):
Program Project1;

{$APPTYPE CONSOLE}
uses
  Windows;

var
  b : Array[0..3000000] of byte;
  i : integer;    
begin
  for i := 1 to 2000 do 
    CreateBitmap(1000,1000,3,8,@b);
  ReadLn;
end.

由于未随后释放的位图对象的分配,这将消耗6GB的会话内存。由于对象不是在应用程序的堆上创建的,所以应用程序内存消耗仍然很低。

但是,不了解更多的应用程序,这是非常难以更具体的。以上是演示您正在观察的行为的一种方法。除此之外,我想你需要调试。

在这种情况下,分配了大量的GDI对象 – 但这并不一定是指示性的,因为在应用程序中分配的GDI对象通常很多,而不是大量的大对象(Delphi IDE例如,将常规地创建> 3000 GDI对象,这不一定是问题)。

相比之下,@ Abelisto的例子(在评论中)

Program Project1;

{$APPTYPE CONSOLE}
uses
  SysUtils;

var
  i : integer;
  sr : TSearchRec;
begin
  for i := 1 to 1000000 do FindFirst('c:\*',faAnyFile,sr);
  ReadLn;
end.

这里返回的句柄不是GDI对象,而是相当于搜索句柄(属于内核对象的一般类别)。这里我们可以看到,该进程使用了​​大量句柄。再次,进程内存消耗很低,但是使用的会话内存大幅增加。

类似地,对象可能是用户对象 – 这些对象可以通过调用CreateWindow,CreateCursor或通过SetwindowsHookEx设置钩子来创建。有关创建每个类型的对象和返回句柄的WinAPI调用列表,请参阅:

Handles and Objects : Object Categories — MSDN

这可以帮助您开始追踪问题,将其缩小为可能导致问题的呼叫类型。如果您正在使用任何组件,它也可能在错误的第三方组件中。

像AQTime这样的工具可以配置Windows分配,但是我不知道是否有支持Delphi5的版本。可能有其他配置分析器可以帮助跟踪这一点。

Windows – 我的32位应用程序可以做什么消耗千兆字节的物理RAM?的更多相关文章

  1. 响应iOS中的RAM可用性

    退后一步,还有其他一些适用于OpenGL纹理内存的自适应技术吗?

  2. 使用iOS上的Memory Monitor,虚拟内存消耗与实际内存之间的差异

    有人说你不应该使用超过100MB.那是真正的记忆,还是虚拟记忆…或者可能是某种组合?我的实际内存一直在20到25MB之间,但崩溃时虚拟内存大约为190–205MB.这是一个截图:有人能够对此有所了解吗?

  3. 如何从命令行更改android模拟器RAM大小?

    我想在命令行创建android模拟器时编辑或更改ram大小.EX:在创建模拟器时,它采用默认的ram大小(AndroidSDK4.0.3)512MB但我想将其增加到768MB或减少到256MB.我想改变只有拉姆尺寸.因为有一个选项可以改变Ram的大小.如果你输入了yes,我们需要提供很多东西.解决方法您需要找到已创建的AVD的配置文件.在我的情况下,我在Ubuntu上运行AVD,所以这是我找到配置

  4. Android应用程序在首次启动时开始非常慢,但通常在下次启动时启动

    我使用Eclipse创建了一个非常繁重的应用程序并在4.2.2设备上部署.在第一次启动时,需要相当长的时间才能完全显示UI.在那之后,即使在app杀死并重新启动之后,一切都会很快,需要0.5秒才能启动.这是正常现象,如果是,那么根本原因是什么?

  5. windows – 在Haskell程序中使用所有可用的RAM?

    我有8GB的RAM,但Haskell程序似乎只能使用1.3GB.我正在使用这个简单的程序来确定GHC程序可以分配多少内存:这是我发现的:>运行./mem.exe40000000RTS-s成功并报告正在使用的总内存为1113MB>运行./mem.exe42000000RTS-s因内存不足错误而失败>运行./mem.exe42000000RTS-s-M4G错误输出-M4G:大小超出允许范围>运行./m

  6. 在Windows桌面上调整postgreSQL以利用24GB RAM

    我的pgtune值看起来好吗?我做了一些研究,告诉我:>在Windows上,shared_buffers不应大于512MB,而应使用该系统缓存.问题:我是否必须以某种方式告诉Windows将系统缓存分配给postgresql,否则如果postgresql请求它会自动发生?>work_mem允许数据库服务器在RAM足够大的情况下对RAM进行排序.问题:我的work_mem足够大吗?如何判断是在RAM还是磁盘上进行排序?我将非常感谢任何有助于加快此查询的见解.谢谢!

  7. 可编程RAM磁盘API for .NET?

    寻找一个RAM磁盘API(或等效的软件实现)来临时存储文件,用于物理硬盘环境之外的读/写操作.更新Exe文件将被写入RAM磁盘并执行.“RAM磁盘”是操作系统级的结构,因为它必须实现一个文件系统和设备驱动程序来模拟一个磁盘.您不能在图书馆级别执行此操作.如果你想追求操作系统级别,Windows自带一个内置的ramdisk.sys驱动程序.否则,将文件读入应用程序中的数据结构将具有与使用RAM磁盘相

  8. centos – mdadm Raid-1是否可以通过网络文件共享?

    我使用的是64位CentOS5.5我知道可以使用物理硬盘和RAM磁盘使用mdadm设置软件RAID1.是否可以使用NFS挂载和RAM磁盘设置mdadm软件RAID1?或者另一种提出问题的方法是,NFS挂载是否可以成为与mdadm一起使用的块设备?

  9. centos – kswap使用100%的CPU,即使有100GB的RAM也可用

    >Linux内核是否应该足够智能,只需从内存中清除旧缓存页而不是启动kswap?

  10. centos – 广泛使用RAM时服务器计算速度减慢

    我在非常具体的情况下遇到服务器速度下降的问题.事实是:>1)我使用计算应用WRF>2)我使用双XeonE5-2620v3和128GBRAM(NUMA架构–可能与问题有关!

随机推荐

  1. static – 在页面之间共享数据的最佳实践

    我想知道在UWP的页面之间发送像’selectedItem’等变量的最佳做法是什么?创建一个每个页面都知道的静态全局变量类是一个好主意吗?

  2. .net – 为Windows窗体控件提供百分比宽度/高度

    WindowsForm开发的新手,但在Web开发方面经验丰富.有没有办法为Windows窗体控件指定百分比宽度/高度,以便在用户调整窗口大小时扩展/缩小?当窗口调整大小时,可以编写代码来改变控件的宽度/高度,但我希望有更好的方法,比如在HTML/CSS中.在那儿?

  3. 使用Windows Azure查询表存储数据

    我需要使用特定帐户吗?>将应用程序部署到Azure服务后,如何查询数据?GoogleAppEngine有一个数据查看器/查询工具,Azure有类似的东西吗?>您可以看到的sqlExpressintance仅在开发结构中,并且一旦您表示没有等效,所以请小心使用它.>您可以尝试使用Linqpad查询表格.看看JamieThomson的thispost.

  4. windows – SetupDiGetClassDevs是否与文档中的设备实例ID一起使用?

    有没有更好的方法可以使用DBT_DEVICEARRIVAL事件中的数据获取设备的更多信息?您似乎必须指定DIGCF_ALLCLASSES标志以查找与给定设备实例ID匹配的所有类,或者指定ClassGuid并使用DIGCF_DEFAULT标志.这对我有用:带输出:

  5. Windows Live ID是OpenID提供商吗?

    不,WindowsLiveID不是OpenID提供商.他们使用专有协议.自从他们的“测试版”期结束以来,他们从未宣布计划继续它.

  6. 如果我在代码中进行了更改,是否需要重新安装Windows服务?

    我写了一个Windows服务并安装它.现在我对代码进行了一些更改并重新构建了解决方案.我还应该重新安装服务吗?不,只需停止它,替换文件,然后重新启动它.

  7. 带有双引号的字符串回显使用Windows批处理输出文件

    我正在尝试使用Windows批处理文件重写配置文件.我循环遍历文件的行并查找我想要用指定的新行替换的行.我有一个’函数’将行写入文件问题是%Text%是一个嵌入双引号的字符串.然后失败了.可能还有其他角色也会导致失败.如何才能使用配置文件中的所有文本?尝试将所有“在文本中替换为^”.^是转义字符,因此“将被视为常规字符你可以尝试以下方法:其他可能导致错误的字符是:

  8. .net – 将控制台应用程序转换为服务?

    我正在寻找不同的优势/劣势,将我们长期使用的控制台应用程序转换为Windows服务.我们为ActiveMQ使用了一个叫做java服务包装器的东西,我相信人们告诉我你可以用它包装任何东西.这并不是说你应该用它包装任何东西;我们遇到了这个问题.控制台应用程序是一个.NET控制台应用程序,默认情况下会将大量信息记录到控制台,尽管这是可配置的.任何推荐?我们应该在VisualStudio中将其重建为服务吗?我使用“-install”/“-uninstall”开关执行此操作.例如,seehere.

  9. windows – 捕获外部程序的STDOUT和STDERR *同时*它正在执行(Ruby)

    哦,我在Windows上:-(实际上,它比我想象的要简单,这看起来很完美:…是的,它适用于Windows!

  10. windows – 当我试图批量打印变量时,为什么我得到“Echo is on”

    我想要执行一个简单的批处理文件脚本:当我在XP中运行时,它给了我预期的输出,但是当我在Vista或Windows7中运行它时,我在尝试打印值时得到“EchoisOn”.以下是程序的输出:摆脱集合表达式中的空格.等号(=)的两侧可以并且应该没有空格BTW:我通常在@echo关闭的情况下启动所有批处理文件,并以@echo结束它们,所以我可以避免将代码与批处理文件的输出混合.它只是使您的批处理文件输出更好,更清洁.

返回
顶部