内存管理优化范文(精选11篇)
内存管理优化 第1篇
随着计算机的广泛应用, 人们开始越来越多的使用网络进行办公、购物以及娱乐等活动, 计算机已经日益成为人们生活中不可缺少的部分。计算机作为一种新兴技术, 也并非十全十美, cpu、主板、软件、硬件等物件的损坏经常会给人们带来许多烦恼。占用内存越来越大, 计算机运行速度越来越慢, 如何保证计算机的正常运行越来越成为人们关注的话题。本篇文章通过对计算机内存的组成分类以及如何优化虚拟内存, 提出了笔者的一些建议, 希望能在一定程度上改善这种状况。
1 计算机内存的分类
传统的计算机内存主要分为五类, 即常规内存、高端内存、扩展内存和扩充内存。常规内存是计算机上的第一块内存区, 是DOS和一般软件直接使用的内存;高端内存紧临着常规内存区, 它通常被系统的硬件使用, 例如显示驱动程序以及一些常驻程序等;扩展内存、高内存以及扩充内存都是对常规内存的扩充, 这里就不一一介绍了, 随着信息技术水平的提高, 内存分类相较于以前也有了一定的简化。
如今的计算机内存主要分为物理内存和虚拟内存, 一般来说, 物理内存是计算机自带、在系统运行中经常使用的内存, 也是我们通常所说的内存条。虚拟内存并不是真实存在的, 是为电脑提供内存扩展服务的。物理内存是计算机临时存放数据信息拷贝的场所, 它是随机存储的, 无法长期保存其中的信息, 它的工作任务是不断地对用户给予的指令进行分类、规划与整理, 当用户下达的指令超过系统承受的范围, 内存就会消耗殆尽。为了解决这一问题, 就需要系统将虚拟内存添加进来。当常规内存不足以满足用户对多种信息的同时需求或者多种软件同时运行的状况时, 计算机自动拿出硬盘的一部分空间作为临时办公场所, 供用户使用。这种附加内存就叫做虚拟内存。举个例子来说, 如果电脑所能处理文件的最大能力是521M的话, 那么让他读取一个700M的文件时就不会读取出来, 这时电脑就会将读取后的文件先储存到虚拟内存, 等到虚拟内存将文件全部储存到虚拟内存之后, 就会把虚拟内存里储存的文件释放到原有的安装目录里了。
2 内存的管理与优化
2.1 内存的管理
如果一台计算机只有物理内存, 处理的程序大多能够在计算机处理能力以内的, 那就不需要计算机的管理了, 因为物理内存中一般都附带基本的管理程序。如果一台计算机的内存不够用了, 多数是由计算机物理内存不够引起的, 如何对物理内存内部的程序进行优化, 是内存优化管理的关键。
为了使用计算机扩展内存、扩充内存或上位内存, 就必须安装内存管理程序, 所谓的内存管理程序是一种针对特定类型的内存进行访问的设备驱动程序, 最常用的内存管理程序是:HIMEM.SYS提供的对扩展内存的访问, EMM386.EXE提供的对上位内存的访问。
2.2 内存的优化
虽然计算机的运行速度对某些行业或者某些用户来说并不是必不可少的, 但是如果计算机的运行速度影响到用户最基本工作或者网络享受时, 就需要对内存进行优化管理。因为计算机从购买之日起, 其硬件配置以及应用程序的设定就已经固定了, 因此用户只能通过对计算机内存的优化进而提升电脑的运行速度。
2.2.1 物理内存优化法
系统在运行的过程中, 会实现对信息的收集、整理、以及存储, 当信息的存储达到一定的数量的时候, 就会占用电脑的物理内存, 因此需要用户经常对系统垃圾进行清理。具体方式:点击开始菜单中的运行程序, 点击运行程序之后会出现一个程序输入框, 在命令行中输入clipboard后按回车。也可以打开剪切板, 在剪切板中释放内存。桌面运行也会占用一定的系统空间, 大量繁杂的快捷方式不仅让电脑看起来不美观, 更重要的是减缓系统的运行速度, 因此桌面要时刻保持整洁, 对于一些不常用的程序进行清理, 通过在控制面板中将墙纸设置为空, 也可以在一定程度上释放内存。
电脑中经常会有一些程序的功能重叠, 例如:360安全卫士和360杀毒在功能上具有一致性, 两者同时使用必然会增加物理内存的占用率。关掉一些功能相近的程序是有必要的。
我们可以通过ctrl+alt+del的组合按键调出任务管理器, 或者用鼠标点击桌面下面的任务栏中任务管理器, 查看电脑正在运行的所有程序以及物理内存占用量, 对于一些不经常使用的程序, 例如flash、视频、网盾之类的程序, 通过开机启动项中的禁止启动来开机禁止, 减少程序在内存中的占用。
2.2.2 虚拟内存的优化
所有计算机程序的使用都是要通过物理内存这第一道防线, 对于一些应用程序较多或者内存储量不足的计算机来说, 物理内存很快就会被消耗枯竭。当物理内存不足以满足程序占用的时候, 系统就需要对物理内存进行过滤, 将一些最近很少使用的程序保存到硬盘当中的虚拟内存中, 以便腾出一些内存空间供新程序使用。当用户对转存虚拟空间中的某些程序有需求时, , 物理内存就会从虚拟硬盘中读取这些数据, 不会对物理内存的占用产生影响。虚拟空间的大小不受其他因素有关, 只与虚拟内存存在的分区硬盘的大小有关, 这就为内存较小的计算机提供了很大的收缩空间。在计算机默认的状况下这些虚拟内存是通过系统来进行管理的, 但是系统管理的方式比较固定, 经常会偶造成页面读取的间断, 从而降低了工作效率。
我们可以用右键点击桌面上“我的电脑”图标, 在出现的菜单栏中点击“属性”, 打开“系统属性”窗口, 然后在窗口中点击“高级”选项卡, 点击之后, 会出现高级设置的对话框, 点击“性能”区域中的“设置”按钮在选项中选中“高级”选项, 打开对话框。在对话框中我们可以看到关于虚拟内存的区域, 点击“更改”按钮见入虚拟内存的设置窗口。选择一个容量较大的分区, 勾选“自定义大小”前面的复选框, 将具体数值填入“初始大小”“最大值”栏中, 依次点击“设置-确定”按钮即可, 最后重启计算机, 虚拟内存设置就会生效。
3 虚拟内存的应用设置
上述内容对虚拟内存优化有一定的涉及, 但是每个人的实际操作不可能都完全相同, 因此, 就需要对虚拟内存做个性化设置。
3.1 常规设置法
根据原有的虚拟内存设置方法, 将内存设置的具体数值进行量化, 以便对大小不同的文件进行具体问题具体分析, 通常虚拟内存在进行交换文件的时候都会有最小值和最大值的设置, 通常情况下最大值和最小值的比重1.5:1, 如果内存本身的容量比较大的时候, 它占用的空间也是比较可观的。因此我们可以按照如下的数值进行设置, 首先, 我们将内存的假定在0MB到512MB之间, 然后取一个规定数值, 在这里我们就取256MB吧, 对于内存容量256MB以下的, 我们就将他设置到1.5倍;在512MB以上的, 我们可以将它设置为内存容量的一半:对于内存容量在256MB与512MB之间的设为与内存容量相同的数值即可。
3.2 精准设置法
由于职业或者娱乐的不同, 有些人会用一些比较大型的工具, 而有些人只是打打字什么的;有些人会玩一些大型游戏, 而有些人钟情于一些小游戏。用法的不同就决定了具体的优化配置也不会相同, 于是我们就需要根据具体的用法, 对虚拟内存做具体化的设置。
首先将虚拟内存自定义中“初始大小”和“最大值”进行设置, 让设置的数值保持一致;然后打开“开始”中的控制面板, 点击“控制面板”中的“管理工具”, 点开“管理工具”之后, 找到“性能”项目, 单击打开, 在出现的项目对话框中找到“性能日志和警报”, 选中其下面的“计数器日志”, 然后在右侧栏目中空白处点击右键, 选择右键菜单中的“新建日志设置”选项, 会弹出一个对话框, 在弹出对话框“名称”一栏中填入名称, 名称内容任意。输入名称内容之后就可以点击“添加计数器”按钮进入下一个窗口。在该窗口中打开“性能对象”然后下拉列表, 选择其中的“paging file”, 勾选“从列表中选择计数器”, 并在下方的栏目中选择“usage peak”, 勾选“从列表中选择范例”在下方的栏目中选择“-totle”, 点击“添加”, 在上述操作完成之后, 就可以点击“关闭”了。
如果想要方便以后对日志的查看, 就可以打开“日志文件”选项卡, 将“日志文件”类型选择为“文本文件”, 最后点击确定即可返回到“性能”的主界面上, 在右侧栏目中可以看出来多出现了一个按钮, 上面标有“虚拟内存测试的标志, 如果这个项目是红颜色标注的, 就说明测试还没有正式启动, 点击该选项, 在右键菜单中启动即可。
上述程序设置完成之后, 工作就基本完成了, 接下来我们就可以运行我们常用的一些程序了, 首先进入系统分区下日志文件的默认目录”perflogs”, 找到“虚拟内存测试-0000001.csv”文件, 这个文件可能用一般双击无法打开打不开, 我们需要在文件上单击右键, 找到打开方式, 然后选择记事本打开, 文件打开之后我们需要查看每一栏中倒数第二项数据, 这个数据就代表着虚拟内存的使用比率, 找到这项数据的最大值, 然后用图中所显示的数据乘上一开始设定的“初始大小”或者“最大值”, 计算之后我们会得到一个数值, 我们就可以用所得到的的数值定义虚拟内存的大小, 虚拟内存的最大值可以通过磁盘的空间大小自由设定, 通常情况下, 我们要将它设置到2到3倍左右。
4 结束语
综上所述, 我们可以看出计算机的物理内存在通常情况下都是固定的, 缓解物理内存的方法只能仅仅的局限在减少程序的使用或者垃圾的清理上面, 很难从根本上改变内存过高的情况。由于虚拟内存的大小由分区磁盘的大小决定的, 因此, 对于虚拟内存的变动就显得简单、灵活一些, 所以文章用了大量的篇幅去介绍虚拟内存的优化管理, 以求达到优化内存的效果。
参考文献
[1]韩广林.优化计算机内存[J].天津师范专科学院.2011 (02)
[2]程显波.计算机的内存管理与优化[J].辽宁石油化工高等专科学校.2012 (05)
内存优化工具的骗局~~~ 第2篇
内存100%显示界面
比如一款名为“内存100%”的应用,AppStore拥有免费与收费两个版本,声称能够提高系统速度优化内存,实际上该应用仅是一个欺诈应用,免费版仅有一个“点击购买专业版”的功能,点击之后需要购买专业版应用,之后悲剧再次产生,购买专业版应用的用户购买的功能仅仅是查看iOS设备内存状态,优化功能完全没有,当然在没有越狱的情况下,这款应用也不可能修改系统内存的情况,也就没有内存清理的功能,让人郁闷不已,
i OS版360手机卫士
例如,“内存100%”的应用在AppStore中还有很多,不过这些应用100%没有权限操作系统内存,更不要提优化内存了,简直是赤裸裸的欺诈。除了“默默欺诈”的应用以外,360手机卫士iOS版也声称支持内存优化,不过360手机卫士正逐渐弱化这个功能,其描述也仅仅是炒作的味道,并未有实际的功效。
越狱设备的所谓优化
内存管理优化 第3篇
Windows XP是微软最成功的操作系统之一,相比Vista和Win-dows 7,XP的市场占有率仍是目前最高的。而即使是较高配置的电脑,在运行XP系统时也会出现因系统内存不足导致速度缓慢等一系列问题,Windows XP为什么会对内存的要求如此之大呢?
原来在Windows XP中的一些自带功能是内存的占用大户,我们只要把这些不常用的功能关闭,操作系统将会变得更加稳定。
第一步:关闭“自动升级”功能
我们要对XP的“自动更新”功能下手,“自动更新”是WindowsXP为了方便用户升级系统而推出的一种新功能,这种功能可以在微软推出系统升级补丁或系统安全补丁的时候,自动提醒用户升级自己的系统。不过这种功能有一个要求,就是用户必须时时在线。但是对于我们这些缺金少银的“穷人”来说,这个要求未免苛刻,所以我们把“自动升级”功能关闭掉,改为“手动升级”。
具体操作:右键单击“我的电脑”,点击属性,点击“自动更新”,在“通知设置”一栏选择“关闭自动更新,我将手动更新计算机”一项。
第二步:关闭“系统还原”功能
我们要对形如鸡肋的“系统还原”功能下手,系统还原功能是微软的一个很富有想象力的创意,不过微软没有能够很好地实现这种创意,所以做出来的系统还原功能只能是食之无味,弃之可惜的鸡肋之作。对用户来说,没什么太大作用,所以我们决定要关闭它以节约内存。
具体操作:右键单击“我的电脑”,点击属性,会弹出来系统属性对话框,点击“系统还原”,在“在所有驱动器上关闭系统还原”选项上打钩。
第三步:关闭“远程桌面”功能
“远程桌面”功能,它的一个特点就是可以让别人在另一台机器上访问你的桌面。在局域网中,这个功能很有用。比如你有问题了可以向同事求助,他可以不用到你的跟前,直接通过“远程桌面”来访问你的机器帮你解决问题。但果对于我们只有一台计算机的普通用户来说这个功能就显得多余了,所以我们把它关掉,不让它在那儿白白浪费内存。
第四步:关闭“自动发送错误”功能
大家在Windows XP中肯定有这样的经历,一旦一个程序异常终止,系统就会自动跳出一个对话框问你是否将错误发送给微软,这就是XP中的“自动发送错误”功能,可这样的功能有什么用呢?除了浪费电话费外,对我们而言没有任何用处,所以我们应该义无反顾地把这项功能关掉。右键单击“我的电脑”,点击属性,点击“高级”一“错误汇报”,选择“禁用错误汇报”功能。
第五步:关闭“视觉效果”中不需要的效果
Windows XP的操用界面的确是很好看。好看的背后是以消耗大量内存作为代价的,相对于速度和美观而言,我们还是宁愿选择前者,右键单击“我的电脑”,点击属性,点击“高级”,在“性能”一栏中,点击“设置”,点击“视觉效果”,在这里把所有特殊的外观设置都关闭掉,我们就可以省下“一大笔”内存。
第六步:关闭“Internet时间同步”功能
“Internet时间同步”,就是使你的计算机时钟每周和Internet时间服务器进行一次同步,这样你的系统时间就会是精确的,不过这个功能对我们来说用处不大,而且还可能引起死机的问题。所以我们要把它关掉。
具体操作是依次单击“开始”→“控制面板”→“日期、时间、语言和区域选项”,然后单击“日期和时间”→“Internet时间”。
第七步:关闭多余的服务
内存管理优化 第4篇
内存数据库 (MMDB, Main Memory DataBase) 是一种将数据完全加载到内存并在内存中实现对数据进行管理的数据库。MMDB对数据库的体系结构进行重新设计, 没有采用传统的磁盘数据管理, 对数据组织结构、索引技术、并行操作等方面进行了相应改进, 有效地解决了基于磁盘的数据库中CPU和磁盘I/O之间的主要矛盾, 和传统基于磁盘的数据库相比, 数据读写速度高出几个数量级, 能够极大地提高应用的性能。MMDB具备基于磁盘数据库的所有特性, 如数据库的定义、存储、维护等数据的持久化管理, 数据增删查改及完整性检查等操作, 事务调度与并发控制, 数据存取的控制和安全性检验, 数据的可靠性恢复机制。
索引影响着数据库的执行效率, 同样, 索引结构在很大程度上决定访问内存数据库的效率等各方面的性能。最常见的B+树由于受节点远大于Cache Line和节点中需存储大量的指针数据等因素的影响, 其Cache访问性能较差。针对此种情况, 一些学者提出了Cache敏感的索引树结构, 比较常见的有CSS树、CSB+树和T树。Cache访问性能是影响MMDB性能的重要因素之一, 而在共享Cache多核处理器条件下, 如果只采用单线程模式执行索引访问, 势必不能充分发挥CMP的并行计算资源;而传统的多线程执行方式, 即每个索引访问线程都需要执行自顶向下的索引遍历, 则会由于CSB+-Trees的根节点层及其子节点层中的节点被重复访问的概率要远大于其它节点层中的节点, 导致索引访问时的时间局部性和空间局部性较差, 而且底层节点数据更容易将项层节点数据替换出共享Cache, 造成共享Cache访问冲突。同时, 由于CSB+树节点较小树高较大, 更降低了线程访问索引数据时的局部性。因此, 以传统的多线程执行方式访问索引, 线程的Cache访问性能不佳, 影响了索引访问的性能。
随着集成电路CMOS制造工艺的持续提高, 单个门电路的尺寸都在不断变小, 基于半导体的微电子技术的物理极限问题成为一个重要的设计所关心的问题。物理极限的影响造成了散热及数据同步问题。对于更复杂、处理能力更强的处理器的需求促使处理器设计人员利用各种各样的可行方案提高处理器的性能。处理器主频、内存访问速度和I/O速度发展不同步已经成为很大的瓶颈, 单纯依靠提高处理器主频来提升整个系统的性能已经不可行, 并行计算技术成为解决之道。线程级并行TLP计算技术对于很多应用场合都是合适的, 它通过利用多个独立的CPU来提高系统的性能。时至今日, 集成电路技术的发展及减少系统占用面积的要求最终促使了多核处理器的出现。多核多线程处理器是通过支持单片多处理器 (CMP) 和同时多线程 (SMT) 的组合来实现的。多核多线程处理器由多个简单的同时多线程处理器核构成, 它提供了一种更加简单有效的方法去提高集成度。它不同于超标量处理器通过硬件来提取指令级的并行, 是通过编译器的支持, 多核多线程处理器可以提供一种线程级的并行。由于它由多个简单的同时多线程处理器, 所以它就可以拥有单片多处理器主频高、设计和验证时间短的优势, 又拥有同时多线程资源利用率高的优势, 从而大大提高程序的运行效率。目前, 越来越多的芯片生产商和研究机构都将注意力放在了多核多线程处理器的研究上。正是因为多核与多线程技术的大量使用, 使得处理器处理能力能跟上时代发展。
2、相关研究[1]
索引影响着数据库的执行效率, 同样, 索引结构在很大程度上决定访问内存数据库的效率等各方面的性能。由于等值查询最为常用, 所以缓存敏感的索引结构通常用来加速查询的速度。以下是常见的3种缓存敏感索引结构。
T树:T树在较早的时候提出, 改善了B+树浪费内存空间的问题, 由于高度过大, 没有做缓存优化, T树的缓存性能还不如B+树。
CSS树:它是Array索引的一种改进, 通过连续存储方式, 去除了节点和数据项的指针, 提高了对缓存的利用率。但树的连续存储方式限制了其动态更新的能力, 因此, CSS树比较适合于数据相对静态的OLAP领域。
C S B+树:它是在B+树的基础上对缓存做优化, 只在节点头部保存了一个指向下层节点组的指针。同时, 兄弟节点之间建立组的概念并连续存储, 通过指针和偏移量定位子节点。这样的设计提高了缓存的利用率, 减少了查询过程中缓存失效的次数。然而, CSB+树的不足在于节点大小都控制在一个缓存块左右, 一般为64Byte和128Byte, 当索引项数很大时, CSB+树的深度很大, 在查询路径上会带来更多的TLB失效问题。
3、相关工作
3.1 基于CMP的CSB+-Trees访问性能优化
基于CMP进行优化, 充分利用多核处理器的并发能力, 需要对原有的索引进行并发改进。首先, 改进索引结构, 将单路查询转为多路查询, 每一路查询用独立的线程处理。然后, 分解每个查询或更新任务, 如并行处理二分查找过程等。最后, 对于批量查找或者更新的任务, 将任务分组, 并行处理每个任务组。
任务池是MSI编程模型的基本组成部分, 同一个任务池中的多个任务可以由不同的线程并行执行。多个任务池可以相互连接, 以描述流水线或其他拓扑结构的任务池依赖关系。如一个包含3个任务池的流水线结构.当任务池1中的子任务执行完成以后, 得到的中间结果便会传给任务池2, 并由任务池2执行再产生中间结果, 如此类推, 直到最后一个任务池执行完任务并输出最终结果, 由此把任务变成流水线式地执行.在此过程中, MSI中的线程调度器将根据各个任务池的负载情况动态调度每个任务池将CSB+树中的节点划分为多个工作集后, 使得基于流水线式多线程执行模式的索引访问时, 每个操作对应的索引访问线程所需处理的索引数据少于传统多线程方式, 减少了底层索引数据将上层索引数据替换出Cache的机率, 从而降低了共享Cache访问冲突, 改善了索引访问时的时间局部性和空间局部性。
执行同一操作的索引访问线程之间, 由于线程执行的运算较少, 索引访问线程l将索引访问线程2将要访问的数据读入最低一级Cache后, 在索引访问线程2访问这些Cache Line之前, 它们被替换出Cache的机率相对较低, 提高了执行相同操作线程间的数据共享。
3.2 基于流水线的CSB+-Trees多线程访问模块
基于流水线式多线程执行模式的C S B+树多线程访问模块, 该模块可用于需要访问索引的查询对应的Q E P执行。该模块与QEP中其它节点的接口为键值缓存, QEP中的投影选择节点为该访问模块提供查找索引的键值即可以基于CSB+-Trees的索引嵌套循环连接为例。QEP中的投影.选择节点将表A中元组的连接列生成键值存入键值缓存 (Key Buffer) qa。其中的CSB+树多线程访问模块对应于QEP中的Key Join和TID Join节点。该模块内部组织成流水线执行模式, 并根据CSB+-Trees的树结构层次设置流水线中的操作。将CSB+树中的节点按照树结构层次分成若干个线程工作集, CSB+-Trees的根节点及其子节点划为工作集WorAgetl, 第三层节点和叶节点层组成工作集WorkSet2。流水线则设置两个操作:Opcratorl和Operator2, Operatod和Operator2对应的索引访问线程分别负责访问WorkSetl和WorkSet2。CSBT-MAM执行时, 流水线中Operatorl对应的索引访问线程访问键值缓存获取键值, 以键值为参数搜索WorkSetl中的节点, 然后将节点指针连同键值存入指针缓存 (Pointer Buffer) 中;Operator2对应的索引访问线程即要从指针缓存中获取键值和节点指针访问余下的索引节点, 也需要获得表B的Tuple ID (T/D) 直接访问表B, 并将结果放入输出缓存 (Output Buffer) 。其中, 所有缓存均采用Parallel Buffer结构, 使得C S B T-M A M的适应性更强, 即使投影-选择操作同样采用多线程执行模式, CSBT-MAM也不会因内存访问而成为整个QEP执行的性能瓶颈。
4、结语
在多核环境下, 存储介质的访问延迟和分支预测错误的延迟在索引的查询和更新所消耗时间中仍占有较大的比重, 有效地减少这些延迟, 对提高索引的整体性能有着重要的作用。增强索引操作的并发性是利用多核处理器特性提高索引性能的重要手段.主要可以从改进索引结构、分解单个查询或更新任务、将批量查询或者更新任务分组等方面入手。
参考文献
[1]Rao Jun, Rosa Kenneth A.Cache conscious indexing for de-cisionsupport in main memory.Proceedings of the 25th VLDB Conference.Edinburgh, Scotland, UK, 1999:78-89.
[2]欧阳炜昊, 李灿辉, 钟山.内存数据库索引技术研究[J].科技创新导报, 2010, 29:25.
优化内存后重新启动时死机 第5篇
到StartingWindows95之后几秒内屏幕下方出现一红色长条,光标停在左上方,死机。
从故障现象分析,问题出在内存分配上。大概是运行优化程序之后,设备驱动程序内存配置被修改,从而Windows95在引导时内存占用发生冲突导致死机。故再次启动机器,在StartingWindows95时,迅下F8键进入DOS7.0。发现AUTOEXEC.BAT及CONFIG.SYS果然被修改,将其改为原样,重新启动,顺利进入蓝天白云,但好景不长,屏幕提示声卡无效,确定后进入Windows95桌面,发现光驱不可访问,无法播放VCD,重装声卡及光驱驱动器程序后,全部恢复正常,
在另一台486DX/100,装有DOS6.22及Windows3.2微机中,运行该程序后,Windows3.2出现启动画面时死机,重装光驱驱动程序,在DOS6.22以下光盘安装Windows3.2系统后才恢复。
内存管理优化 第6篇
关键词:Objective-C;内存管理;应用
中图分类号:TP311.11
在编写程序的过程中,有效和高效地管理内存资源是程序开发人员需要着重考虑的事情,一方面是为了保证应用程序的内存消耗尽可能低,另一方面是为了防止内存泄漏。为此,Cocoa定义了一些有助于内存管理的规则和原则。内存管理所要做的就是清理不用的内存,以便内存能够再次利用,即以某些方式确定一个对象不再需要使用了,并且它占用的内存能够被回收。
1 Objective-C内存管理规则
Cocoa提供了一种被称为“引用计数”或“保留计数”的机制,内存管理被放在对象创建与销毁的生命周期中,该机制不同于C语言中有方法(malloc/free)直接操作内存,也不同于GC语言自动管理内存。实际上,这种内存管理方式使得每一个对象都有一个引用计数,当对象被创建的时候,其引用计数为1;当引用计数减少到0时,对象会被销毁。
在Objective-C中,所有对象都被定义为指针;指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址,如果使用不当,就会出错或者造成内存的泄露。因此,在进行内存管理时,需要了解内存管理规则。Objective-C内存管理规则的主要内容:(1)把对象视为内存,只能释放或自动释放所拥有的对象。(2)当使用含有alloc、new、copy的方法创建对象,便拥有该对象的所有权;或者向对象发送retain消息,也会拥有该对象的所有权。(3)当不再使用对象时,向对象发送release或autorelease消息,将会释放对象的所有权。通常,在不适合立即回收对象的情况下才使用autorelease。(4)通过实现dealloc方法来释放所拥有的实例变量。(5)自由释放池(@autoreleasepool),即自动引用计数(ARC机制),这是一种半自动机制,可以手动设置或取消。自动内存释放使用@autoreleasepool关键字声明一个代码块,当代码块执行完之后,对象都会自动调用一次release方法,同时对象的销毁过程也得到了延迟(统一调用release方法)。
2 常见错误及对策
内存泄露主要是指由于设计的失误对某块内存失去控制,而这块内存不能被再次使用,导致了内存的浪费。当发生内存泄露或别的内存问题时会比较麻烦,因为编译器不会自动发现这类错误,通常是在程序运行时才能捕捉到;同时,Objective-C 2.0后引入的ARC机制,也不能完全避免内存泄露等问题。避免内存问题、解决内存泄露的办法:(1)为了防止内存泄露,当使用alloc或copy创建了对象,或者使用retain保留了对象,我们都必须通过release方法释放。(2)改写dealloc方法,在需要的时候释放内存。(3)手动创建autoreleasepool,该方法使得无须等待系统释放所创建的对象,便可告诉系统在代码段结束时释放对象。(4)大多数情况下,申请内存的语句数量和释放内存的语句数量应该相等。
3 应用实例
以下是内存管理的一个例子,首先定义了一个类Student,包含两个实例变量name和age,自定义相应的setter和getter方法,并手动管理内存,该例子给出了一个内存泄露的情况,并在最后给出解决方案。
3.1 Student类的接口文件的定义:
3.2 Student类的实现文件的定义:
3.3 主方法main的实现如下:
从运行结果发现,当对象stu的实例变量name被字符串s2=”Jacky”重新赋值,此时,原来定义的字符串s1不再使用,但是它的引用计数仍然为1,到最后它所占用的内存都没有被释放。
导致这种问题的产生的根源在-(void)setName:方法上,当[stu setName:s1]时,name拥有了s1的使用权;接下来,当用户使用[stu setName:s2]来替换了原来s1的值时,并没有对name发送release消息,那么name对于s1的使用权就没有释放,但此时name的值已被s2所取代,即此刻name拥有了s2的使用权,而s1不再使用,而此时s1的引用计数仍为1,所占用内存没有正常回收,故产生了内存泄露。
为了解决该内存问题,我们在原来的-(void)setName:方法中,增加[name release];这行代码(即原方法中被注释掉的一行),该代码使得原来name没有正确释放它所拥有的对象的使用权的问题得到解决,相应的内存管理过程也正确了。同时,需要说明的是,当初次执行[name release];时,name的值为nil,而在Objective-C程序中,向nil发送任何消息都不会报错。
4 结束语
综上,只要掌握了Objective-C中的内存管理的正确方法和步骤,很多不必要的内存问题和内存泄露是完全可以避免的。
参考文献:
[1]杨正洪,郑齐心,李建国.Objective-C程序设计[M].北京:清华大学出版社,2011.
[2]Stephen G.Kochan著,林冀,范俊,朱奕欣译.Objective-C程序设计(第4版)[M].北京:电子工业出版社,2012.
[3]Scott Knaster,Waqar Malik,Mark Dalrymple著,周慶成(译).Objective-C基础教程(第2版)[M].北京:人民邮电出版社,2013.
作者简介:任艳(1982.04-),女,教师,讲师,硕士研究生,研究方向:现代数据库技术。
内存管理优化 第7篇
对于手机来说,内存资源是非常有限的,良好的内存分配管理机制是至关重要的.如果内存没有得到良好的分配及捕获清理,会导致内存溢出、数据丢失,系统崩溃等严重后果发生。本文主要是讨论在Symbian开发过程中,内存管理机制的实现过程和一些注意事项。
Symbian操作系统的一个显著特点是针对内存空间和资源均受限的设备设计的,所以高效的使用这些有限的资源成为重点。作为手持设备的开发者,必须要注意以下几个问题:
(1)有效率的编程,减少对RAM的不必要的使用;(2)资源使用完毕后尽快释放;(3)需要对资源不足情况进行处理,这要求在每次内存分配的时候都进行;(4)如果在程序运行过程中出现内存不足的情况,应该使程序回到一个可以接收的稳定状态,并且清除在此过程中分配的资源。上述考虑对于一个成功的手持设备开发者是非常重要的。一个手持设备的操作系统如果不能够在以上问题上对开发者提供良好的支持,则无疑它是失效的。
Symbian OS主要提供了三种机制来管理内存的。它们分别为:TRAP和Leave、清除栈、两阶段构造函数。
1 TRAP和Leave
在开发Symbian OS的时候,异常处理还不是C++标准的一部分,所以Symbian没有采用C++后来引进的抛出/捕获异常处理方法,而是使用了自己的异常退出/捕获方法作为简单高效的轻量级的异常处理机制。Symbian OS使用User::Leave()、User::LeaveI-fError()等系统函数来抛出异常,提供TRAP和TRAPD两个宏来捕获异常,这与标准C++中的throw和catch类似。
1.1 抛出异常
Symbian OS中的函数并不返回出错代码,而是一出现资源不足错误时就抛出异常。Symbian OS使用User::Leave()、User:LeaveIfError()等系统函数来抛出异常。
(1)User::Leave():该函数的原型为static IMORT_C void Leave(TInt aReason);该函数将导致程序回溯到最近的异常捕获模块,并将异常代码aReason传递给异常捕获模块。所有可以异常退出的函数都以字母'L'结尾。
(2)User::LeaveIfError():该函数的原型为static IMORT_C void LeaveIfError(TInt aReason);如果aReason为负数,该函数将导致程序回溯到最近的异常捕获模块,并将异常代码a Reason传递给异常捕获模块;如果aReason为非负数,该函数仅返回aReason。
1.2 异常捕获
在Symbian OS中,出现的错误和异常要能够及时捕获并处理。Symbian OS提供了TRAP和TRAPD这两个宏来捕获异常。TRAP与TRAPD功能是一样的,它们使用的区别在于,TRAPD声明的变量包含了错误代码,TRAP只不过少了变量声明,因此需要自己在程序声明一个变量来保存错误值.以下是TRAP与TRAPD的比较:
需要注意的是:大量的TRAP会增加可执行文件的大小和影响程序的执行速度。因为每次进入和退出TRAP宏都会导致内核执行调用,在运行时还需要分配一个结构体来保存异常退出发生时栈的内容,这样当异常退出发生并沿调用栈传播时,才有可能恢复现场的状态。因此,尽量少使用或者替代使用TRAP,会节省很多资源。不要连续使用多个TRAP,而是利用方法Leave,从而将错误交给调用者处理。
2 清除栈
正常申请堆空间后,堆和栈的空间分配如图1所示。如果一个函数产生异常,程序会回溯到异常捕获模块。这意味着栈空间中的自动变量都被删除了。如果这些栈空间的自动变量包含有指针,而自动变量指针通常会指向一个堆空间,堆空间的对象永远不会被删除,这时就发生了比较严重的问题:内存泄露。如图2所示。
清除栈就是用来处理这个问题的。它用来保存那些在发生异常后需要释放资源的对象指针。当Leave发生时,通过保存在清除栈中的指针,来删除它们所指向的对象。如下代码所示:
当我们申请完Cclanger并得到它的指针clanger后,立即将指向Cclanger的自动变量指针Push到清除栈中。然后调用InitializeL()或DoSomethingElseL();如果它们没有Leave,则CleanupStack::PopAndDestroy(clanger)被执行,将指针clanger从清除栈中弹出并将对象Cclanger删除;如果InitializeL()或DoSomethingElseL()发生了Leave,Trap harness将调用PopAndDestroy()来清空清除栈上所有从调用Trap时压进去的变量,并释放相应的堆空间。如图3所示,加入清除栈后栈和空间的分配图。
当发生异常退出后,指针clanger和自动变量被栈空间管理进程删除,此时CClanger对象内存空间由清除栈中的clanger*来释放,避免了内存泄露。
需要注意的是,在使用清除栈时,有压入就要有弹出,保证清除栈的压入和弹出操作在逻辑上是匹配的。只能把自动变量压入清除栈,而非成员变量,因为Symbian C++实际上有两种清除机制,一种是清除栈,另一种是析构函数。这两种机制各有分工,并行不悖。在发生异常后,成员变量的清除工作由析构函数来处理。如果将成员变量压入清除栈,则该变量会被清除两次。
3 两阶段构造函数
当在堆上进行实例化过程中,首先,程序为类的实例化申请内存,执行成功;紧接着,程序执行该类的构造函数,又要申请内存,但系统内存耗尽,执行失败。在这种情况下,若不触发异常退出,则构造函数不能将初始化失败的信息传递出来,我们接收到的对象指针指向的是一个构造不完全的对象。这将对之后的程序运行产生不可预知的影响。如果触发异常退出,则程序回溯到最近的异常处理模块,进行相关的异常处理。可是程序已经为该类的实例化申请了内存,但其指针却没有及时加入到清除栈,此时就会造成内存泄露。
上述问题的主要症结就在于类的构造函数可能发生异常。于是将此问题一分为二对待,得到两阶段构造函数,即将一个对象的构造分为两个阶段:第一个阶段是不能异常退出的构造函数;将可能产生异常的初始化操作从构造函数中抽出,放在第二个阶段中,用函数ConstructL()来实现。
对象的构造过程包括了如下的代码:
CClassName*self=new(ELeave)CClassName();//第一阶段构造
CleanupStack::PushL(self);
self->ConstructL();//第二阶段构造
CleanupStack::Pop(self);
从以上代码我们可以看出,每实例化一个对象就要写上述代码有些过于麻烦,为了简化过程,Symbian OS又引入了NewL()NewLC()两个静态函数,典型的NewL()和NewLC()实现如下:
CClassName*CClassName::NewLC()
{
CClassName*self=new(ELeave)CClassName();
CleanupStack::PushL(self);
self->ConstructL();
return(self);
}
CClassName*CClassName::NewL()
{
CClassName*self=CClassName::NewLC();
CleanupStack::Pop(self);
return(self);
}
可以看出,NewL()构造的对象,没有被压入清除栈,NewLC()构造的对象被压入清除栈中。我们可以根据具体情况选择使用。有了NewL()和NewLC()后,再创建CclassName时,就可以用代码CClassName*iClassName=CClassName::NewLC();或者
CClassName*ClassName=CClassName::NewLC();了,从而程序得到大大简化。
4 结束语
Symbian操作系统是专门针对内存空间及资源均受限的设备设计的,它在内存空间管理方面有着不同于其他平台的特有机制,内存管理更加高效,有效的避免了内存泄露造成的严重后果。但其高效的内存管理是以牺牲兼容性为代价的,相信Symbian OS在今后的发展中会不断地完善不足之处,其兼容性也会越来越高。
参考文献
[1]马建,陈健.智能手机操作系统编程-Symbian及60系列[M].北京:科学出版社,2005.
[2]董佩嘉.Symbian异常处理及预防研究[J].电脑知识与技术,2007(2).
[3]郑朝霞,赵岚.基于Symbian S60的内存管理[J].软件导刊,2008(8).
JAVA内存管理模式研究 第8篇
JAVA自上个世纪90年代初期诞生以来, 发展到今天已经被业界广泛的认可, 其为编程 (尤其是网络编程) 方面所带来的巨大变革, 是其他语言所不可比拟的。它以自身的纯粹的面向对象, 分布式, 安全性, 健壮性, 与平台无关性等特点正在被全世界的程序员所推崇。但伴随而来的也有一些质疑, 比如JAVA在编制桌面程序, 以及在程序的执行效率方面确实还有差强人意的地方, 其原因何在?本文试就上述问题, 从内存的角度分析JAVA的内部机制, 以使读者更深入地了解和掌握JAVA语言。
二、Java的内存分配策略
JAVA程序在运行时, 不同平台上的JVM都会提供如下图所示的运行时数据区组件:
JAVA是如何来管理分配内存的呢?Java的内存分配主要有三种:一是方法区, 存放静态变量和方法信息。该区域在程序编译时就分配好了空间大小, 为了避免导致编译程序无法计算准确的存储空间需求, 这种分配方式要求程序中不能有不确定的数据结构, 更不允许有嵌套, 甚至于递归等结构的出现;二是栈区, 即各种原始数据类型的局部变量都是在栈上创建出来的, 并且当程序退出该变量的作用范围的时候这个变量的内存就会被自动释放。和方法区的分配相反, 在栈区, 程序在编译时对数据的状态是未知的, 这要到运行时才能知道。三是堆区, 该区域负责分配在编译时和运行时都不能确定存储需求的数据结构的内存, 如对象 (包括数组) 都是在堆中创建的。程序在运行时通过new关键字来创建对象, 对象创建时会在堆中为其分配内存, 当对象不再被用到时, 会被GC垃圾回收机制自动回收, GC这时就必须监控对每一个对象的运行状态, 如对象的申请、引用、被引用、赋值等, GC都需要进行监控, 其目的是简化了程序员的工作。但却加重了JVM的工作。这也就是为什么Java程序运行速度较慢的原因。
除了这三个区域外, 还有寄存器和常量池。其中的寄存器, 由于处在处理器内部, 所以运行起来速度肯定是最快的, 但是由于其容量非常小, 且是直接受处理器控制而非人为控制, 所以我们无法掌控。常量池是用来存放确定性的符号引用的, 如类和接口的全限定名, 字段和方法的描述符等。
三、JVM中堆和栈的区别与比较
在JAVA中, 栈与堆在内存中都被Java用来存放数据。Java自动管理栈和堆, 这一点与C++不同。单纯从功能作用来说, 堆主要用来存放对象, 栈中一般用来存放一些基本类型的变量和对象句柄。
(一) 栈 (stack) , 存在于RAM中。
栈对内存的操作方式是, 从处理器那里得到指令后, 通过内部的“栈指针”来具体执行, 指针向下移动就是分配一个新内存给变量;如指针向上移动, 则代表释放该部分内存。这种分配方式方便快捷, 效率仅次于寄存器。由于栈在运行时要确定所有数据的大小以及它们的“生命周期”, 以便操作栈指针进行相应的移动, 这就对程序的灵活度造成了一定的影响。所以, JAVA只是把所有的局部变量, 形式参数以及对象的句柄变量等分配到栈中, 因为这些内容在运行时都可以是确定的。另外, 方法调用也是在栈内进行的, 调用方法的时候, 栈为该方法的参数及局部变量分配空间, 当方法调用结束以后, 这部分空间会被自动释放出来。
栈的特点决定了它的优势是速度快, 存取效率仅次于寄存器。但存于其中的数据大小与生存期在运行时需要被确定, 使得灵活性不够, 则是其缺点所在。
(二) 堆 (heap) , JAVA中对象和数组的生成是在堆中完成的。
以往一般的编程语言不会选择在堆中分配内存资源, 因为效率较低。但是JAVA中由于引入了自动垃圾回收机制 (GC) , 使得堆中分配内存的速度明显加快, 甚至于能够接近于其他语言在栈中分配内存的速度。其内存分配的具体过程是这样的, 在JVM中保存有一个堆指针, 指向于堆中未被分配的内存, 当生成一个新的对象时, 该指针只需改变一下内部的记录并做一个简单的移动操作, 指向下一片未分配空间, 所以效率会跟栈不相上下。但如果单纯这样操作而不采取一些其他辅助措施, 在生成新对象时势必会造成频繁的内存分页并产生大量的内存碎片, 使得内存的消耗很大, 进而影响到系统性能。出于这方面考虑, JAVA中引入了GC的内存管理机制, GC在检测到内存资源紧张时被自动调用运行, 在程序中从根节点开始去找所有的对象引用, 当发现某个对象不再被用到时, GC会自动收回该对象所占用的堆内存空间并加入到空闲列表里, 留待下一次分配内存时使用, 在这一过程中还会对堆中的对象内存进行优化, 使它们紧密排列在一起, 这样一来就使得一些零散的内存碎片重新组合在了一起, 从而避免下一次分配内存空间时分页失误的现象发生。显然, GC机制的引入, 减轻了程序开发人员的工作任务, 降低了程序代码的复杂度, 并在一定程度上控制了系统中潜在的危险因素。但GC在内存回收方面不是万能的, 它只负责监控由new生成的对象, 而且运行过程中消耗时间, 所以, 在编程中我们要科学地安排代码, 尽量避免有过多内存垃圾产生。比如, 当对象不再被使用时应显式将其赋值为null, 以便节省GC检测时所消耗的时间。
堆的优势是在运行时动态地分配内存, 而内存的管理交由GC自动处理, 从而实现了高速、自由、灵活的堆空间分配模式。
(三) 关于二者存储效率方面的比较。
我们用如下示例来说明:
我们把Test_1类中这两种创建对象的形式做下比较, 第一种用new的形式, 系统读到new关键字的时候就在堆内存中生成一个新的对象保存起来。每读到一次new就生成一个新对象。第二种形式则是先在栈内存中生成一个对String对象的引用的一个变量str2, 然后查找栈中有没有存放"qjw"字符串对象的变量, 若没找到的话, 则将str2指向”qjw”字符串对象, 如果已经有指向于”qjw”对象的变量存在, 则直接令str2中的值等于该变量中保存的地址值。
在程序中我们来验证一下:
上面的结果验证了str1和str2是指向于同一个对象的。而实际上在内存中只有一个对象而已, 这种做法有利于节省内存空间, 同时它可以在一定程序上提高程序的运行速度, 因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str=new String (“qjw”) ;的代码, 则一概在堆中创建新对象, 每读到一次new, 就在堆内存生成一个新对象。而不管其字符串值是否相等, 是否有必要创建新对象, 从而加重了程序的负担。
四、结语
本文从内存的角度详细分析了堆内存和栈内存的特点及区别, 通过二者的比较, 目的在于使读者能对JAVA在内存管理方面有更深入一层的了解, 从而在编程中对内存的使用方面更加得心应手, 对于学习理解乃至于编写JAVA程序都非常重要。通过比较我们知道, 虽然栈的优势是存取速度比堆快, 但其灵活性方面还显得很欠缺。而堆的优势却是可以在运行时动态地分配内存大小, 在内存管理方面更加灵活, 因为有Java内置的垃圾收集器帮助其对内存进行管理, 但这也要付出一定的开销, 因为GC随时在监测内存中对象的存续状况, 以便发现不用的对象及时对其进行回收, 所以在某种程度上就付出了效率的代价, 但总体上不失为JAVA在内存管理方面的优秀表现。
摘要:由于JAVA的纯面向对象的特性, 编程中会频繁地进行对象的操作, 深入理解对象及变量方法等在内存中的分配过程有助于设计合理高效的程序, 对于Java虚拟机优化垃圾收集及程序的能耗优化有着重要的指导意义。本文通过对Java虚拟机内存区域的分析, 对内存的分配问题进行了详细地阐述。
关键词:Java, 堆内存,栈内存,静态域,常量池,内存分配
参考文献
[1].章婧, 卢凯.JAVA程序内存行为研究[J].小型微型计算机系统, 2011
[2].黄山, 杨全胜, 杜中军.Java内存管理和内存泄漏的研究[J].中国民航飞行学院学报, 2009
[3].黄珍, 刘涛.JAVA中对栈与堆的一点思考[J].九江职业技术学院, 2009
内存管理优化 第9篇
从平台开发的角度,Symbian支持多种面向对象的编程语言。其中,以Java和C++为典型代表,前者注重于界面表示型应用,如手机游戏,依靠Java的跨平台优势,减少开发过程中的适配成本;而基于C++的Symbian应用通过API触及Symbian系统的内核,充分发挥其系统特性。作为典型的嵌入式系统,Symbian的运行环境中,不具有类似PC机的系统资源,所以Symbian系统的内存管理机制较标准的C++更为严格。主要是讨论Symbian C++开发过程中,内存管理机制的实现和注意事项。
1 TRAP与异常处理
应用程序中的对象,可以物理存储于系统的栈区或堆区。栈区中的对象,在其生命周期结束时会自动被系统回收,而堆区内的对象,需要程序员人为的控制器生命周期。
图1中,CClass的对象通过运算符new被分配于系统的堆区,一旦遗漏了内存释放语句delete cls,则会产生内存泄露。频繁的内存泄露会造成Symbian系统无内存可用的窘境。此时,若再次动态申请内存,则会产生内错不足的异常。
Symbian操作系统,使用TRAP机制,来捕获异常。图2中的示例代码给出了TRAP的使用方法:使用动态内存分配操作符new时,在后边加入ELeave标识符,一旦无法分配内存,则会产生异常;在调用CreateObject方法时,需要借助于TRAP宏函数,一旦异常产生,则可在应用程序中捕获并处理之。
TRAP机制保证了内存操作的安全性,应用时需要注意:首先,并非所有异常都需要前端程序员处理,一旦有异常产生,将逐步上溯至系统内核,通常情况下,程序员可以将95%的错误上交给系统处理,不要自己处理;其次,TRAP的代价很高,不要连续使用多个TRAP,而是让方法Leave,从而将错误交给调用者处理;最后,需要特别注意,在进行动态内存分配时,不要习惯于C++的new操作符,Symbian平台中,需要使用new(ELeave),其本质是对new操作符的重载。
2 Cleanup Stack结构
TRAP机制保证了系统内存分配的可用性,但并未杜绝内存泄露的发生。Symbian OS使用清除栈(Cleanup Stack)结构来屏蔽系统级的内存泄露。
图3中给出了典型的Cleanup Stack的应用场景:动态内存分配之后,首先将新产生的对象的地址存入清除栈中,而后进行其他操作(记为操作A),再次将对象指针弹出清除栈。需要注意,之所以需要进行进栈与出栈操作,是因为操作A中可能会发生异常,造成程序中断。
当应用程序发生如图4所示的异常时,清除栈的作用就得到体现。首先,ojb1指针进栈之后,在创建obj2时发生了内存异常,程序产生Leave,直接被TRAP捕获。TRAP机制中,会调用CleanupStack::PopAndDestropy()静态方法,这就保证了obj1被正常释放,而不会对系统运行的内存造成泄漏。
应用清除栈结构时,需要明确:在一个可能Leave的函数中产生的,栈上指向C类对象的自动变量指针要Push到清除栈中;一旦出现了异常,TRAP将调用PopAndDestropy()来清空清除栈上所有从调用TRAP时压进去的变量,并释放相应的堆空间;当不会出现Leave时,需要将对象指针从清除栈中弹出。
3 两段对象构造
第二小节的图3中,给出两段构造的基本特点。
第一阶段是C++的构造函数,在第一阶段中,不能出现Leave,也不能处理失败,因此需要将可能失败的语句移出构造函数。需要注意,复杂的类对象才采用两阶段构造。
第二阶段构造函数ContructL()则是进行可能Leave的构造。最终,使用工厂函数NewL将二者放在一起,实现了两阶段构造。
两段构造的主要目的仍旧是保证不会发生内存泄露。面向对象编程中,构造函数是一个特殊的函数,它的调用不受程序员的控制,在C++规范中,动态内存分配运算符具有调用构造函数的责任。new的工作原理是:首先分配内存空间给新对象,而后调用新对象类别的构造函数,进行初始化对象操作。极端情况下,系统的堆区内存资源已经十分有限,分配对象本身空间时,内存尚且够用,对象成功分配;不幸的是,下一步调用对象的构造函数时,需要再次申请堆区内存,此时发生异常退出。那么,这种情况下,已经分配给对象的内存将不再受控制,造成内存泄露。因此,必须改变C++中new的标准动作,使用两段构造保证内存使用的合理性。
为了实现两步构造,必须屏蔽类型的构造函数,如图5所示,可以将构造函数声明于类私有成员之中,保证不被外界调用。同时,实现静态的NewL方法,静态方法可以被外界直接调用。
需要特别指出,Symbian OS对两步构造的支持,通常表现为NewL静态方法或者NewLC静态方法,前者用于指针对象分配在堆中的情况,而后者表示指针对象还保留在清除栈中的情况。图6中的示例代码,给出了二者实现上的区别。
4 结语
智能手机平台具有相对PC机小的系统资源,而其上的应用往往具有运行时间会很长、极少重启的特点,即使少量的内存泄漏经过积累也会造成灾难性的后果。在Symbian OS上开发程序必须是没有内存泄漏的,因此所有分配的堆内存必须至少有一个指针关联且所有堆内存必须在使用完以后尽快释放。Symbian系统的TRAP机制、清除栈结构和两段对象构造方法保证了其内存管理的科学性与严格性,是程序员必须遵循的系统级标准。
摘要:Symbian操作系统中,使用TRAP机制捕获系统异常,控制内存分配过程。清除栈结构可以保证当发生异常产生的情况下,系统不会出现内存泄露。对自定义类型的两段构造方法,可以修改C++默认的构造规则,保证内存安全。
关键词:Symbian操作系统,内存管理,内存泄露
参考文献
[1]Forum Nokia Carbide.C++Introductory White Paper[Z].August13,2007.
[2]Forum Nokia Carbide.C++FAQ[Z].June18,2008.
[3]姚盛旺.Symbian OS C++程序开发[J].计算机与数字工程,2007,(01).
内存管理优化 第10篇
Android是基于Linux2.6内核的操作系统, 它是专门为移动设备设计的操作系统并且是一个强内核版本, 在21世纪初, 是科技发展的时代, 在Android出现一年后, 以Android为品牌的Android手机也横空出世。本文主要析了以linux2.6为基础, 阐述Android3.0内存管理所作的创新。
2 Android的后台机制
Android在使用的过程中, 会消耗很多地RAM, 主要是因为属于Java的范畴。它所打开的应用程序都带有一个Java虚拟机, 所以这样做有很大的好处, 当单一的程序遇到崩溃时, 并不会影响到系统的稳定性, 算是一个有益的Android特性。其实, Android平台在保证多任务的同时兼具了兼顾稳定性和速度, 但是由于其他的平台给用户带来的思维定式, 使得很多的Android用户认定后台只要开多了就自然会变慢, 自然会缩短续航的时间。
3 Android 3.0内存管理方面的新技术
在内存管理方面, linux系统新旧两个版本 (Android2.6之前和Android 3.0) 存在着很大的区别。Android是一个强内核版本, 本文主要分析了Android3.0内存系统的管理的。为了能Android更好地在移动设备上运行, Android 3.0内核在linux2.6的基础上, 内存管理方面作了很大的改进, 尤其是针对连续大内存页。Android体制比较繁琐的系统, 当开启一个系统时就必然地耗费时间。如何能够使得系统运转地更快些, 就是当你关闭一个程序时, Android的系统反映会迟钝, 并不会立即处理它。这样如果使用者重新开启系统时, 速度就会变快。但是大量的程序在系统里, 会占据许多的内存, 然后就出现了低内存管理Android (low Memory Killer) 机制。
3.1low Memory Killer
Low Memory Killer系统在操作过程中, 会定时的对内存使用情况进行检查, 如果内存被严重占据时, kswapd会将shrinker进行回转, 有序地收存各种页面。Lowmem_shrink是这个驱动最主要的机制, 通过采用lowmem_shrink的方法来处理被占据的内存, 这样就会保证有空余的内存。函数实现要选择一个内存, 被选的进程要满足以下条件:1.进程优先级最低 (oom_adj最大) , 不能小于提前将lowmem_adj等级分类;2.所占据的物质空间要最大。在系统被扫描的每个进程, 通过对比规定的准则选择一个进程, 最后调用force_sig函数把删除进程的信号发送至内核。如果系统内存比临界值低时, 所去除的准则是由oom_adj和进程所占用的具体空间所决定。但是因为系统的操作比较随性, 有可能使系统容易出现故障。
3.2PMEM
PMEM的作用是使一些运行设备能够有效的提高工作效率, 主要由no_allocator模式、allocator模式组成, 1.no_allocator模式是指以个性化的共享物内来迎合整体, 2.allocator模式是指PWEM的整体被分割成若干个小块进行。通过三种构造去保护内存空间 (pmem_info、pmem_data、region_node) , 分别表的是设备分配的共享内存块、内存的其他分部系统。pmem_region_node将pmem_data分成若干个部分, pmem_info里不同层次的部分都会与跟pmem_data有一定的关联。
在allocator系统的运转模式里, pmem_allocate采用了最有效的方法对内存精细的择诀, 然后, 通过相关的设备对扫描后的部分选择性的比较, 然后对老版的best_fit进行处理, 增加最新版本。结束后, best_fit就是记录所要求的内存块。
在PMEM采用最佳适应算法后, 页面的内存都被占据着, 这就会使页面变得不完整。当系统达到内存共享时, 要先有序地开启一个进程, 然后才可得到获得PMEM。ALLOCATE所分部的内存空间, 就成为了一个进程, 并修改pmem_data->flags为PMEM_FLAGS_MASTERMAP, 其他的进程再重新开启这个PMEM设备, 分配到另外一个pmem_data, 成为client进程, 将master pmem中的一些收集到自己的空间里, 就可以达到共享的目的。共享内存为任意数量进程之间提供高效双向通信的平台, 为了能够避免读取信息之前覆写内存空间等竞争状态的出现, 使用者在读取写入数据的同时, 所有程序之间必须要达成一定的协议, 但是不能确保Android对共享内存块的唯一访问。
3.3 匿名内存Ashmem
在Android系统中, 提供了独特的匿名共享内存子系统叫ASHMEM, ) , 它以驱动程序的形式实现在内核空间中它有两个特点:一是能够辅助内存管理系统来有效地管理不再使用的内存块, 二是它通过Binder进程间通信机制来实现进程间的内存共享。它能够有效地改进内存管理系统的管理方法。当系统内存处于紧张状态时, 管理系统就会采用一种方法将有效的内存空间进行回收, 保留有用的内存, 这样能够提高内存的利用率。因此, 当系统加大了内存的空间时, 系统就会换成ashmem_shrink, 就会命令Ashmem程序完成此项操作;ASHMEM通过调用shmem_file_setup, 从内存的文件系统自己创立一个文件给ashmem_area, 然后将其分散到的内存传入相关的空间里, 这样就实现了共享的进程。ASHMEM提供了PIN/UNPIN机制, 通过对系统的相关要求, 找出与内存相契合的页框, 将找出的页框进行特殊的绑定最后, 如果要增加内存的空间, 系统便遵循相关的规定, ashmem_range_>lru链表上的页框回收。
4 Android 3.0内存优化研究
4.1 低内存页面的回收的要求
那些被选定的进程准不是单一, 而是更加多元化。比如, 需要综合考虑CPU、存活寿命、等内存消耗量值, 经过综合的评判, 才能进行理性的评分。
4.2 低内存机制耗费的时间
Android系统中杀程序的这个刽子手被称作"LowMemory Killer", 它是在Linux内核中实现的。这里它实现了一个机制, 由程序的重要性来决定杀掉谁。也就是, 谁抛锚了, 先杀掉谁。所以, 系统设置了时间格式在适当的时间会对其进行体检, 像这样的机制要使用时要慎重。如果要提高机制的工作效率, 可以在系统的相关部位设置一个定时器, 但系统提示进入哪个进程时, 就不能尚自的将其处理, 是显示出黄牌的警告, 截止下次扫描累计两次, 才可启动lowMemoryKiller, 并删除其进程。
除了本文所提到的这些外, Andoid3.0的内存管理部分要改进的地方还有许多, 一些细节方面的改进也要重视, 在未来所要探索的方面还有很多。要合理的使用内存, 正确地认识到任务管理器Android内存原理, Android大多应用没有退出的设计与系统的调度机制有关。Android的内存管理比起Linux, 在设计上还是有很大的创新, 在功能与技术上为移动设备取得了巨大的突破。对于Android的内存管理实际上可以借鉴到每一步进程, 他们之间是相通的。除此之外, Android的使用范围也不断地在扩张, 在未来, Android内存管理系统的发展会越来越快。
摘要:Android是基于linux平台, 于2007年谷歌公司所研发的移动设备操作系统, 本文针对Android 3.0系统的内存管理的研究, 对Android系统作了简要的概述, 分析了Android 3.0在内存管理方面的新技术以及未来所要研究的方向。
关键词:Android,内存管理系统,新技术,方向
参考文献
[1]杨丰盛.Android技术内幕[M].北京:机械工业出版社, 2011.
[2]汤小兵.计算机操作系统[M].西安:电子科技大学出版社, 2009.
实时JAVA虚拟机的内存管理研究 第11篇
Java语言的面向对象,平台无关,安全,开发效率高等特点,使其在许多领域中得到了越来越广泛的应用,但是由于Java程序由于自身的局限性,使其无法应用于实时领域。Java程序是运行在Java虚拟机上,而Java虚拟机是计算机体系结构的一个软件实现,由软件模拟来实现各个Java指令解释和执行,这在一定程度上影响了其性能[1]。由于内存管理对Java虚拟机的实时性具有非常大的影响,通过深入研究Java虚拟机的内存管理机制,改善其内存管理的实时性,对于实现Java虚拟机整体的高效率、高可靠性、高可预测性都具有很大的实际意义。
2. 实时JAVA虚拟机的框架设计
实时Java虚拟机可以说是实时系统的一个实例,不过它是一个运行于操作系统和硬件平台之上的实时系统。实时Java虚拟机要保证在其中运行的Java程序具有实时特性,而它自身又是运行于操作系统之上,其实时性很大程度上依赖于该宿主操作系统所提供服务的实时性。因此要实现实时Java虚拟机,需要有实时操作系统的支持[2]。实时Java虚拟机系统框图见图2-1所示。
3. 实时JAVA虚拟机的内存管理
3.1 内存区域的模型设计
内存区域 (Memory Area) 的基本模型如图3-1所示。内存区域信息包含了一个一个指针指向其所维护的内存空间,因此通过内存区域信息就可以找到内存空间。同时内存区域信息是有层级关系的,每个内存区域可以包括多个子内存区域。
对于任何一个Java对象来说,它都包含了两个部分,一部分是由Java语言实现的Java类,另一部分是其在Java虚拟机内部对应的数据结构。Java的执行引擎执行Java类中的程序,同时维护其对应的虚拟机内部的数据结构。由于Java程序的运行是解释型的,显然维护虚拟机数据结构比维护Java数据结构更加高效,且更具有确定性。要提高Java程序的实时性,就要把Java类中核心部分更多的由虚拟机来维护和处理。
在内存空间中的对象都是Java对象实例,这些对象可分为普通对象和内存区域对象。内存区域对象也是一个普通的Java对象,它不仅可以分配在堆区域内,还可以分配在其它任何的内存区域内。内存区域的数据结构定义如下:
每个内存区域都由其父内存区域来管理,即由父内存区域来决定其分配和释放的方法。每个父内存区域内部都维护着其第一层子内存区域的链表,这样层层的父子关系就构成了一棵树。因为虚拟机刚启动的时,对象都是创建在堆中的,所以堆内存区域必然是所有内存区域的父亲。
3.2 内存区域的堆栈管理
内存区域需要在Java虚拟机中良好的管理,分配和释放。区别于传统的Java虚拟机所有的线程都只使用唯一的一个内存区域堆,实时Java虚拟机的多个生命期不同的内存区域是由各个使用它的线程中的领域堆栈 (Scope Stack) 来管理的。检查对象引用规则时需要领域堆栈来保存区域内存嵌套关系,每个线程有自己的领域堆栈。在创建一个实时线程时,领域堆栈初始化如下:
如果该线程是在区域内存中创建,则它的初始领域堆栈包含了其创建时双亲线程领域堆栈结构的副本;如果该线程在堆或永久内存中创建,它的领域堆栈结构初始化为只包含堆或永久内存。之后随着线程的推移,领域堆栈不断地把区域内存压入或弹出,保存它们嵌套使用的层次关系。
实时JAVA虚拟机提供了三种方法来进入一个区域内存,此后的空间将在此区域进行分配,直到退出该区域或进入另一个区域。
New thread:在创建一个线程时,把一个区域内存 (ma) 句柄作为参数传递给该线程,该线程默认的空间分配将在该区域内存中进行。
enter:当每次调用ma.enter () 方法时,把ma压入该线程的领域堆栈。同时该线程默认的空间分配将在ma进行,直到enter () 方法返回,或进入另一个区域。
executeInArea:用法和enter () 类似,区别是该线程的领域堆栈不变,只是使用已在领域堆栈中的区域内存。
3.3 内存分配的时间管理
针对内存分配时间的问题,实时JAVA虚拟机的内存管理机制中的Scoped Memory可以派生出3个子类CTMemoy, LTMemory, VTMemory,内存管理机制对它们分配对象的时间有不同的要求。CTMemory要求在其中分配对象的时间是常数时间,LTMemory要求在其中分配对象的时间与对象的大小成正比,VTMemory要求在其中分配对象的时间是任意的,由于没有限制,它更关注于在空间上高效的分配内存。
此外,由于新增的内存区域中的对象可能会引用堆中的对象,因此垃圾收集的过程中也需要扫描新增内存区域中对象的字段,不过不会回收新增内存区域中的对象。
3.4 对象引用的规则管理
由于内存区域的生命期的不同,有些内存区域的生命期与Java虚拟机的生命期相同如Heap Memory和Immortal Memory,而有的生命期是短暂的,与操作它的线程相关,如Scoped Memory。这就引发了内存区域间的引用关系的问题。总的来说,生命期长的内存区域中的对象的字段不能引用生命期短的内存区域中的对象,因为当后者被销毁的时候,而前者由于继续存活而变成非法引用,这就要求建立一个合理而高效的内存引用检查机制。内存区域间的引用关系要求如表3-1所示。
为了方便多个线程共享领域内存时对象引用规则的检查,实时JAVA虚拟机的内存管理提出单亲规则,如果单亲规则不成立,对象引用规则一定不成立。单亲规则是指:每次往领域堆栈 (Scope Stack) 加入一个区域时都要确保它只有一个双亲。双亲是领域堆栈 (Scope Stack) 上相邻的外层领域内存、堆或不朽内存。
如图3-2,线程T1在内存区域Ma3中创建了一个对象O1,在Ma1中保存了O1的引用变量R1。线程T2在Ma2中创建了一个对象O2,在Ma1中保存了O2的引用变量R2。单独就T1和T2来说,都符合对象引用规则。但图3-2中,Ma1的双亲分别是Ma3和Ma2,违犯了单亲规则。假设T1线程退出Ma3后,没有其它线程使用,Ma3被释放掉。这时Ma1中的R1就成了悬空引用。所以在多线程共享区域内存的情况下,首先要保证单亲规则成立,再进一步针对每个线程检查对象引用规则。
4. 总结
总之,Java虚拟机内存管理在很大程度上依赖于Java虚拟机的实现,不同的Java虚拟机的实现对于其内存管理的性能也有一定的影响。但是其理论研究归纳起来主要有两个方面:一是对于领域内存的分配和释放问题,要求具有可预测性和高效性等;二是内存引用检查机制的效率问题,由于Scoped Memory的引入,要求在其中的对象的引用要遵循一定的规则。
摘要:改善JAVA虚拟机的内存管理对于系统的性能影响重大。本文在明确内存管理重要性的基础上, 分析了实时JAVA虚拟机的框架设计, 并详细研究了实时JAVA虚拟机的内存管理, 涉及到:内存区域的模型、内存区域的堆栈管理以及规则管理等。
关键词:实时系统,虚拟机,内存管理
参考文献
[1]南兆阔, 须文波, 柴志雷.一种实时JAVA处理器的数据通路研究[J].微计算机信息, 2008, (29) .