加载和释放NSImage时内存持续增加

2023-12-08

我遇到一个问题,我的应用程序在连续加载图像文件时会大量消耗内存到“崩溃点”。例如,考虑以下代码,该代码重复加载和释放 15MB JPEG 文件(用于测试目的的大文件大小):

NSURL *inputUrl = [NSURL URLWithString:@"file:///Users/me/Desktop/15MBjpeg.jpg"];  
for(int i=0; i<1000; i++) {  
    NSImage *image = [[NSImage alloc] initWithContentsOfURL:inputUrl];  
    [image release];  
}

由于有足够的可用系统内存,它在前几次中执行得很快,但最终系统在我所说的“崩溃点”处崩溃了。在这里,我相信系统释放了足够的内存来加载下一个图像,因此性能最终会变慢。此外,现在其他应用程序运行缓慢,因为系统必须释放这些占用但现在未使用的内存。

对我来说有意义的是,如果它分配内存,然后让系统释放它,以便活动监视器中的“真实内存”统计数据保持较小,而不是通过连续的加载/释放迭代进入千兆字节。实际上,我可能永远不会在这一点上结束,但奇怪的是,当任何时候所需的实际驻留内存通常都很小时,我的活动监视器“Real Mem”统计数据最终超过了所有其他应用程序。我最初认为这是某种内存泄漏或缓存问题,但它似乎与应用程序中的积极内存分配和系统上的惰性内存释放更相关(如果操作系统有该策略,则不是有任何问题 - 如果是这样)事实上它的工作方式)。也许我完全错过了一些东西。

有没有更好的方法来重复加载图像,而不会出现这种占用而不主动释放内存使用行为?也许有一种方法可以强制减少应用程序内存占用,或者有一种方法可以更智能地了解如何将图像加载到相同的对象或内存位置?我的目标是加载图像,处理它(获取缩略图,更改图像格式等),在内存中删除它,然后再次执行 - 所有这些都不会观察到内存增长。

--

跟进:

巴伐利亚,谢谢。包装 NSAutoreleasePool 确实可以解决加载同一文件时迭代内存增长的问题:

NSURL *inputUrl = [NSURL URLWithString:@"file:///Users/me/Desktop/15MBjpeg.jpg"];  
for(int i=0; i<1000; i++) {  
    NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
    NSImage *image = [[NSImage alloc] initWithContentsOfURL:inputUrl];  
    [image release];
    [apool drain];
}

但是,它并没有解决图像释放后(并且 NSAutoreleasePool 耗尽)内存仍然增加的问题。例如,当加载我的 15MB JPEG 图像时,“Real Mem”内存从 8MB 稳定状态跳到大约 25MB,然后停留在那里。 (我的应用程序只有一个 Interface Builder 按钮,该按钮具有连接到仅调用我复制的 for 循环的方法的 IBAction )。我希望在 for 循环完成后(或者如果只加载和释放一张图像),“Real Mem”统计数据将减少回名义应用程序级别的内存使用量。

调用 NSImage 功能时也可以加载后台的其他内容,这似乎是合理的,这可以增加内存。然而,不同大小的图像(15MB、30MB、50MB 等)会按比例增加应用程序中的内存,这让我相信它不仅仅是这样的分配。

此外,如果我尝试连续加载单独的图像(例如 15MBjpeg-1.jpg、15MBjpeg-2.jpg 等),则内存有时加载每个新图像的化合物。例如,如果连续加载两个图像,则加载/释放后应用程序的“Real Mem”内存使用量现在约为 50MB,并且根据我的观察,它永远不会减少。加载后续图像时,此行为会继续存在,因此应用程序在加载多个大图像后可能会占用数百 MB 的“Real Mem”内存。

有趣的是,如果我一遍又一遍地重新加载相同的图像,稳态内存不会增加。这是否表明正在进行某种缓存?同样,我的目标是在不增加内存的情况下对几个不同的图像文件进行批处理。提前致谢。

哦,我正在研究 Heapshot Analysis 文章 ATM,但至少想发布我的进度并看看是否有其他输入。

--

后续#2

bbum,感谢这篇精彩的文章。我用我的测试程序运行了 Instruments Allocations,但没有发现任何堆增长。正如所引用的博客文章中所述,我的方法是,1)单击 Interface Builder 界面上的“加载和释放图像”按钮(调用加载/释放行为),2)每隔几秒单击几次“标记堆”在“工具分配”中,然后 3) 重复 1) 和 2)。

使用这种方法,随着时间的推移,Heapshots 在堆增长列中始终报告 0 字节(每 5 秒点击 3 次,持续 15 秒),这意味着没有从基线 Heapshot 分配额外的内存。另外,在“统计”窗格中,每次单击“加载并释放映像”按钮时都会有 13.25MB 的 Malloc,但 Live Bytes 为 0 字节,这意味着它已完全释放。如果我单击“加载和释放映像”按钮三次,则映像的总字节数报告为 39.75MB (3 * 13.25MB),这意味着已分配 39.75MB,但由于实时字节数为 0,因此已完全释放。分配图快速上升并立即下降,因为这是一个相当快的操作。内存的稳态使用没有泄漏也没有增长,这一切似乎都是有道理的。

但是,现在我该怎么办,我的“Real Mem”统计数据仍然很高?我知道活动监视器不是调试内存问题的标准。但是,“Real Mem”仍然保持高位,直到我关闭程序,然后“Real Mem”全部回到“免费”类别,这对我来说很奇怪。

我通过在相同的方法中复制代码,使用两个图像(15MBjpeg-1.jpg、15MBjpeg-2.jpg)测试了相同的方法,并且我再次观察到没有堆增长。显然,已经进行和释放了更多的分配。然而,现在“Real Mem”的增量大约是仅加载和释放一张图像的情况的两倍。同样,在测试程序的稳定状态下它不会减少。

我还能做些什么吗?以下是单个图像加载/释放的测试代码,供任何想要尝试的人使用(只需将 IB 按钮连接到 openFiles):

#import "TestMemory.h" // only declares -(IBAction) openFiles:(id)sender;
@implementation TestMemory
-(IBAction) openFiles:(id)sender {
    NSURL *inputUrl = [NSURL URLWithString:@"file:///Users/me/Desktop/15MBjpeg.jpg"];
    NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
    NSImage *image = [[NSImage alloc] initWithContentsOfURL:inputUrl];
    [image release];
    [apool drain];
}
@end

谢谢阅读。 :)

--

后续#3

bbum,不,我没有启用垃圾收集(GC 在项目设置中设置为不支持)。我使用 vmmap 和仪器分配中的 VM Tracker 栏研究了内存。当您提到 VM Instruments 时,我假设您指的是 VM Tracker 数据,因为它报告的信息与 vmmap 相同。使用“加载和释放映像”按钮打开单个映像后,一些重要的内存数字包括以下内容(来自 VM Tracker):

Type         %ofRes  ResSize  VirtSize Res%  %AllDirty  DirtySize
__TEXT       38%     33.84MB  80.45MB  42%   0%         0Bytes
*Dirty*32%     28.23MB  114.99MB 24%   100%       17.11MB
MALLOC_LARGE 14%     13.25MB  13.25MB  100%  0%         4KB
Carbon       11%     9.86MB   9.86MB   100%  20%        3.46MB
VM_ALLOCATE  9%      8.43MB   48.17MB  18%   49%        8.43MB
...

有趣的是,单个图像的后续加载/释放会增加该图像的“驻留大小”Dirty和 VM_ALLOCATE 类型约 0.3MB,并且这些类型的“脏大小”也会随着时间的推移而增加。 (VM_ALLOCATE 似乎是一个子集Dirty)。其他类型似乎不会随着后续加载/发布而改变。

我不确定要从这些数据中删除什么,或者如何使用它来使程序释放内存。看起来 VM_ALLOCATE 类型可能是未释放的块,但这只是猜测。底层 NSImage init 实现的某些部分是否可能保存图像文件的缓存并且不会释放它?再次,如前所述,令我感兴趣的是,与第一次加载/释放相比,同一图像文件的每次后续加载/释放几乎不消耗资源(CPU、磁盘研磨等)和挂钟时间。提前致谢。


  • 巴伐利亚说了什么;你有没有尝试过用一个围绕它NSAutoreleasePool.

  • 这是一个经典的微基准。虽然它肯定表明存在问题,但问题实际上可能是基准与预期的现实世界模式相差如此之大,以至于错误在于基准。

  • 在高效设计的应用程序中,它不会多次从磁盘读取相同的图像数据。

  • 这是一个主要候选人爆头分析.


(感谢您的关注,很有帮助!)

您描述的症状听起来像是虚拟机泄漏(某些东西正在消耗地址而不进行分配;例如映射内存)或未修剪的缓存(包含虚拟机分配)。

  • 你有GC启用吗?如果是这样,很可能是因为 GC 阈值未触发。收集器不知道将非 GC 中的真正大量分配记入 GC 区域。如果您强制进行集合,它将解决这个特定的边缘情况。

  • 尝试查看 VM 工具或在命令行中使用 vm_map 来查看应用程序中的地址空间被消耗的情况。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

加载和释放NSImage时内存持续增加 的相关文章

  • TextView、iOS 和 OSX 中的彩虹文本

    我正在尝试向我的应用程序添加一些不同的文本颜色以融合到图像中 我收到了很多用户想要彩虹文本颜色并重复的输入 例如这个词 stackoverflow看起来像这样 s red t orange a yellow c green k blue o
  • VS2010 .NET 内存分析 - 非常慢

    运行 VS2010 的 NET 内存分配分析需要很长时间才能完成 该程序本身运行了大约 3 分钟并生成了 35GB 的内存分配 探查器的输出文件约为 28GB 报告分析流程接管三个小时 在具有 8GB RAM 的双 Xeon 上 即可完成
  • NSImage 到 NSBitmapImageRep

    如何将 NSImage 转换为 NSBitmapImageRep 我有代码 NSBitmapImageRep bitmapImageRepresentation NSBitmapImageRep ret NSBitmapImageRep s
  • Java 开发人员在 Mac OS 上遇见 Objective-C

    很多年前我就用 C 进行过开发 但现在我主要是一名 Java 软件工程师 鉴于我拥有一部 iPhone 准备下个月购买 MacBook 并且总体上对开始 Mac OS 开发 使用 Objective C 感兴趣 我想我应该提出这个问题 下一
  • 如何在 Windows 7 中模拟内存不足的情况

    我有一个用 C 编写的应用程序 运行良好 但有时在现场会出现错误 我们认为这些错误是由于内存不足或与垃圾收集器的交互造成的 如果有人感兴趣 这里有描述 无法将 NHibernate Impl ExpandedQueryExpression
  • 如何在Mac的cocoa应用程序中允许用户的主文件夹的权限

    我有一个 Mac 应用程序 其中我正在从用户的主目录中删除一些数据 我的应用程序被拒绝 原因如下 The app only finds files in the Downloads folder It would be appropriat
  • 用强/弱自我打破保留周期

    我读过关于强 弱的帖子self打破保留周期 但我仍然对它们如何工作感到困惑 我理解使用 weak typeof self weakSelf self创建对自我的弱引用 但我对强引用感到困惑 据我了解 强引用是指对self这样它就不会在块结束
  • 如何在 Mac OS X 的 Cocoa 上绘制文本内阴影

    如何在 Cocoa for Mac OS X 中的文本上绘制内部阴影 我对 NSView 进行子类化 以创建一个带有渐变背景和内部阴影文本标题的占位符控件 stackoverflow 上所有当前 Core Graphics 的答案似乎都解释
  • NSMenuItem 中的自定义 NSView 未接收鼠标事件

    我使用 popUpStatusItemMenu 从 NSStatusItem 中弹出一个 NSMenu 这些 NSMenuItems 显示了一堆不同的链接 每个链接都通过 setAction 连接到目标的 openLink 方法 这种安排长
  • 双击打开 Excel 工作簿时,Excel 2010 AddIn 未加载

    我为 Excel 2010 编写了一个加载项 如果我从 开始 菜单打开 Excel 它可以正常工作 但是 如果我双击 Excel 工作簿 则无法加载 AddIn 我签入了ThisAddIn cs 方法InternalStartup 没有参与
  • 使用 NSCoder 编码 CGPoint 结构

    如何编码和解码CGPoint结构使用NSCoder 编码 CGPoint point point from somewhere NSValue pointValue NSValue value point withObjCType enco
  • NSPredicate 格式字符串不起作用

    在我的代码中 我想检查记录是否已存在 以便我知道是创建它还是更新它 但我遇到了一个问题 问题是当我使用这个时 NSPredicate pred NSPredicate predicateWithFormat ATTRIBUTE ID idN
  • Windows 中内存分配的限制+我计算得是否正确?

    我正在编写一个需要大量内存的程序 大型图形分析 目前我的程序中有两个主要的数据结构 占用了大部分内存 这些都是 n n 类型的矩阵int 和长度为 n 的数组 类型Node 在本例中 节点是一个包含两个 int 的结构体 sizeof No
  • 如何释放字符串未使用的容量

    我正在程序中处理很多字符串 这些字符串数据在读入我的程序后的整个生命周期内都不会改变 但由于 C 字符串保留了容量 因此浪费了大量肯定不会被使用的空间 我尝试释放这些空间 但没有成功 以下是我尝试过的简单代码 string temp 123
  • 为什么 WebView 中的 dataWithPDFInsideRect 不能在 Mavericks 上创建高质量的 PDF?

    Run 示例项目 https github com tvarghese TestWebView并观察桌面上生成的输出 PDF 名为保存网页 pdf 粘贴感兴趣的代码片段 NSURL url NSBundle mainBundle URLFo
  • 原生插入符位置 macos cocoa

    我希望能够使用 cocoa 或 appleScript 获取 Mac High Sierra 中任何应用程序内的全局插入符位置 我已经使用 NSEvent 来获取键盘和鼠标挂钩 但是有没有办法获取插入符位置挂钩 插入符号与鼠标位置不同 它会
  • Java:为什么它使用固定数量的内存?或者它如何管理内存?

    JVM 似乎使用了一些固定数量的内存 至少我经常看到参数 Xmx 对于最大尺寸 和 Xms 对于初始大小 这表明 我感觉 Java 应用程序不能很好地处理内存 我注意到一些事情 即使一些非常小的示例演示应用程序也会加载大量内存 也许这是因为
  • 为什么在 10.5 上我必须在 NSWindowController 上调用 showWindow 两次?

    我有一个 NSWindowController 的子类 我用它从笔尖加载窗口并将其显示在屏幕上 下面是当我想显示窗口时调用的代码 在 10 6 上 当调用 showCustomWindow 时 会显示窗口 但在 10 5 上 必须调用此方法
  • C++中delete和delete[]的区别[重复]

    这个问题在这里已经有答案了 可能的重复 C 中的删除与删除 运算符 https stackoverflow com questions 2425728 delete vs delete operators in c 我写了一个包含两个指针的
  • Cocoa 基于文档的应用程序中的 MVC

    我目前正在对我的应用程序进行重构和重组 我意识到模型和视图及其控制器之间的一些分离已经减少 我希望进行一些清理 我的应用程序中使用了几个关键类 NSPersistentDocument NSWindowController 和模型类 NSP

随机推荐

  • 如何在 ruby​​mine 中停止/终止服务器(开发)

    这里是新手 我在 ruby mine 中创建了一个 Rails 项目来运行公共文件夹中的默认 index html 我按下了 shift F10 键 这与终端的 Rails 服务器相同 这就是我得到的 home bubble rvm rub
  • Java:转义 XML 文本内容而不是整个文本

    我想发送下面的 XML 请求 文本内容应该被转义 但标签不应该被转义 我试过了使用下面的转义逻辑 String str escapeXml11 req 然而 我的整个请求都被逃脱了 因此 它不再是有效的 XML 我原来的字符串 String
  • 在 Flexbox 中组合行和列

    我有三个元素article 照片 类别 然后是帖子信息 我试图弄清楚如何让类别元素堆叠在帖子信息列的顶部 2 在 3 的顶部 如果您正在查看所附照片 因此它看起来像两个 50 的列 即使有是三个弹性元素 flexbox display fl
  • 如何更改 gWidgets RGtk2 中鼠标光标的形状?

    在gWidgets中的ggraphics绘图区域中 将鼠标光标更改为 GDK TCROSS 但我想要与gwindow GDK LEFT PTR 相同的鼠标光标 library gWidgets library gWidgetsRGtk2 l
  • 球拍中的树形折叠

    我是 Racket 的初学者 我有这样的问题 定义一个结构 node 其中包含以下字段 value left middle right 该结构表示树结构中的节点 这些字段包含存储在节点 左子树中的值 分别为中子树和右子树 如果一个子树 不存
  • EntityFramework Core 自动迁移

    有没有代码可以实现自动迁移Entity Framework core code first在 asp net core 项目中 我只是在 MVC4 5 中添加 Database SetInitializer new MigrateDatab
  • Python 向量化嵌套 for 循环

    我希望能够帮助您找到和理解一种 Pythonic 方法来优化嵌套 for 循环中的以下数组操作 def func a b radius Return 0 if a gt b otherwise return 1 if distance eu
  • 在 Laravel Post 中授权资源控制器不起作用?

    我创建了一个 ProductPolicy 其中有
  • PHP:将表单中的值插入 MySQL

    我创建了一个users表中mysql从终端 我正在尝试创建简单的任务 从表单插入值 这是我的dbConfig file 这是我的Index php
  • Android Telegram 应用程序 --> java.lang.UnsatisfiedLinkError: 未找到 void 的实现

    不幸的是 几周前 Stackoverflow 上删除了一个类似的问题 我必须提出一个新问题 我正在尝试通过源 为Android构建一个自己的Telegram应用程序https github com DrKLO Telegram 我无法让它工
  • 如何使用选项字典关闭 Swift 中的 Core Data Write-Ahead 日志记录?

    如何使用 Apple 新编程语言 Swift 关闭 Core Data 中的 SQLite 预写日志记录 WAL 在 ObjC 中 我曾经在选项字典中传入键值对 journal mode DELETE storeCoordinator ad
  • 稀疏签出后过滤 git 提交历史记录

    git repo 下有几十个文件夹 但我只与其中之一合作 所以 我不想知道其他文件夹下的项目发生了什么 我从远程签出了一个启用了稀疏签出的分支 现在我本地只有一个文件夹 但使用 gitk 时我仍然可以看到完整的提交历史记录 我在交互式变基期
  • 如何处理.NET Winforms中的堆叠控件?

    我有一个表单 它将多个面板控件堆叠在一起 每个控件都根据表单上的其他选定选项显示 隐藏 在表单设计器中管理起来确实很痛苦 因为面板的行为不像完整的 TabControl 但是 您似乎无法在没有选项卡的情况下使用 TabControl 处理这
  • 使用 PDFBox 拆分大型 Pdf 文件会得到大型结果文件

    我正在使用 pdfbox 处理一些大型 pdf 文件 高达 100MB 大约 2000 页 有些页面包含二维码 我想将这些文件分割成更小的文件 页面从一个二维码到下一个二维码 我得到了这个 但结果文件大小与源文件相同 我的意思是 如果我将一
  • 具有从 C# 到非托管驱动程序的嵌入式指针的编组结构

    我正在尝试使用 P Invoked DeviceIoControl 调用将 C NET Compact Framework 3 5 与 Windows CE 6 R2 流驱动程序连接起来 对于 IOCTL 代码之一 驱动程序需要一个 Dev
  • 当准备 segue 数组不包含数据时(使用 swift)

    根据按下的按钮 我想将单词列表附加到在开始时声明的变量 pickedList 当我准备继续时 它会覆盖已添加的内容 并且仅使用开始时添加的空数组 我可以在准备继续位中添加项目并将这些项目转移过来 但这不是我想要的 我对编程非常陌生 并且进行
  • JavaFx - 更新 GUI

    我想要的只是在程序运行时更新标签 我正在读取一些文件 我希望它显示正在读取的文件的名称 但是 它仅使用以下代码显示最后一个文件 基本上 GUI 在整个过程完成之前不会响应 static Text m status update new Te
  • 在 Windows 10 中启用 cURL

    我已经在笔记本电脑上设置了本地服务器 Windows 10 家庭单语言 64 位版本 1803 我已经下载并手动安装apache24 php7 MySQL php我的管理员 and 文字新闻通过遵循这个tutorial 我正在尝试启用 cU
  • 从mysql数据库提取数据时如何在mpdf中换行

    我正在使用 MPDF 从 mysql 数据库中存储的数据生成 pdf 文件 虽然我可以按预期提取和显示其他数据 但我无法显示多行文本 因为它们都在单行中 有人可以帮我解决这个问题吗 例如 我来自文本区域的数据在数据库中显示为 一 Two T
  • 加载和释放NSImage时内存持续增加

    我遇到一个问题 我的应用程序在连续加载图像文件时会大量消耗内存到 崩溃点 例如 考虑以下代码 该代码重复加载和释放 15MB JPEG 文件 用于测试目的的大文件大小 NSURL inputUrl NSURL URLWithString f