- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Lua性能优化技巧(五):削减、重用和回收由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
当处理Lua资源时,我们也应该遵循提倡用于地球资源的3R原则——Reduce, Reuse and Recycle,即削减、重用和回收.
削减是最简单的方式。有很多方法可以避免使用新的对象,例如,如果你的程序使用了太多的表,可以考虑改变数据的表述形式。一个最简单的例子,假设你的程序需要操作折线,最自然的表述形式是:
。
尽管很自然,这种表述形式对于大规模的折线来说却不够经济,因为它的每个点都需要用一个表来描述。第一种替代方式是使用数组来记录,可以省点内存:
。
。
对于一个有一百万个点的折线来说,这个修改可以把内存占用从95KB降低到65KB。当然,你需要在可读性上付出代价:p[i].x比p[i][1]更易懂.
。
另一个更经济的做法是使用一个数组存储所有x坐标,另一个存储所有y坐标:
原有的 。
现在变成了 。
使用这种表述形式,一百万个点的折线的内存占用降低到了24KB.
。
循环是寻找降低垃圾回收次数的机会的好地方。例如,如果在循环里创建一个不会改变的表,你可以把它挪到循环外面,甚至移到函数外作为上值。试对比:
。
和 。
相同的技巧亦可用于闭包,只要你不把它们移到需要它们的作用域之外。例如下面的函数:
。
。
我们可以通过将内部的函数移到循环外面来避免为每次迭代创建新的闭包:
。
。
但是,我们不能把aux移到changenumbers函数之外,因为aux需要访问limit和delta.
。
对于多种字符串处理,我们可以通过使用现有字符串的索引来减少对创建新字符串的需要。例如,string.find函数返回它找到指定模式的位置索引,而不是匹配到的字符串。通过返回索引,它避免了在成功匹配时创建新的字符串。当有必要时,程序员可以通过调用string.sub来获取匹配的子串[1].
当我们无法避免使用新的对象时,我们依然可以通过重用来避免创建新的对象。对于字符串来说,重用没什么必要,因为Lua已经为我们做了这样的工作:它总是将所有用到的字符串内部化,并在所有可能的时候重用。然而对于表来说,重用可能就非常有效。举一个普遍的例子,让我们回到在循环里创建表的情况。这一次,表里的内容不再是不变的。通常我们可以在所有迭代中重用这个表,只需要简单地改变它的内容。考虑如下的代码段:
下面的代码是等同的,但是重用了这张表:
实现重用的一个尤其有效的方式是缓存化[2]。基本思想非常简单,将指定输入对应的计算结果存储下来,当下一次再次接受相同的输入时,程序只需简单地重用上次的计算结果.
。
LPeg,Lua的一个新的模式匹配库,就使用了一个有趣的缓存化处理。LPeg将每个模式字符串编译为一个内部的用于匹配字符串的小程序,比起匹配本身而言,这个编译过程开销很大,因此LPeg将编译结果缓存化以便重用。只需一个简单的表,以模式字符串为键、编译后的小程序为值进行记录.
使用缓存化时常见的一个问题是,存储计算结果所带来的内存开销大过重用带来的性能提升。为了解决这个问题,我们可以在Lua里使用一个弱表来记录计算结果,因此没有使用到的结果最终将会被回收.
在Lua中,利用高阶函数,我们可以定义一个通用的缓存化函数:
。
对于任何函数f,memoize(f)返回与f相同的返回值,但是会将之缓存化。例如,我们可以重新定义loadstring为一个缓存化的版本:
。
loadstring = memoize(loadstring) 新函数的使用方式与老的完全相同,但是如果在加载时有很多重复的字符串,性能会得到大幅提升.
如果你的程序创建和删除太多的协程,循环利用将可能提高它的性能。现有的协程API没有直接提供重用协程的支持,但是我们可以设法绕过这一限制。对于如下协程:
这个协程接受一项工作(运行一个函数),执行之,并且在完成时等待下一项工作.
。
Lua中的多数回收都是通过垃圾回收器自动完成的。Lua使用渐进式垃圾回收器,意味着垃圾回收工作会被分成很多小步,(渐进地)在程序的允许过程中执行。渐进的节奏与内存分配的速度成比例,每当分配一定量的内存,就会按比例地回收相应的内存;程序消耗内存越快,垃圾回收器尝试回收内存也就越快.
如果我们在编写程序时遵循削减和重用的原则,通常垃圾回收器不会有太多的事情要做。但是有时我们无法避免制造大量的垃圾,垃圾回收器的工作也会变得非常繁重。Lua中的垃圾回收器被调节为适合平均水平的程序,因此它在多数程序中工作良好。但是,在特定的时候我们可以通过调整垃圾回收器来获取更好的性能。通过在Lua中调用函数collectgarbage,或者在C中调用lua_gc,来控制垃圾回收器。它们的功能相同,只不过有不同的接口。在本例中我将使用Lua接口,但是这种操作通常在C中进行更好.
collectgarbage函数提供若干种功能:它可以停止或者启动垃圾回收器、强制进行一次完整的垃圾回收、获取Lua占用的总内存,或者修改影响垃圾回收器工作节奏的两个参数。它们在调整高内存消耗的程序时各有用途.
“永远”停止垃圾回收器可能对于某些批处理程序很有用。这些程序创建若干数据结构,根据它们生产出一些输出值,然后退出(例如编译器)。对于这样的程序,试图回收垃圾将会是浪费时间,因为垃圾量很少,而且内存会在程序执行完毕后完整释放.
对于非批处理程序,停止垃圾回收器则不是个好主意。但是,这些程序可以在某些对时间极度敏感的时期暂停垃圾回收器,以提高时间性能。如果有需要的话,这些程序可以获取垃圾回收器的完全控制,使其始终处于停止状态,仅在特定的时候显式地进行一次强制的步进或者完整的垃圾回收。例如,很多事件驱动的平台都提供一个选项,可以设置空闲函数,在没有消息需要处理时调用。这正是调用垃圾回收的绝好时机(在Lua 5.1中,每当你在垃圾回收器停止的状态下进行强制回收,它都会恢复运转,因此,如果要保持垃圾回收器处于停止状态,必须在强制回收后立刻调用collectgarbage("stop")).
最后,你可能希望实施调整回收器的参数。垃圾回收器有两个参数用于控制它的节奏:第一个,称为暂停时间,控制回收器在完成一次回收之后和开始下次回收之前要等待多久;第二个参数,称为步进系数,控制回收器每个步进回收多少内容。粗略地来说,暂停时间越小、步进系数越大,垃圾回收越快。这些参数对于程序的总体性能的影响难以预测,更快的垃圾回收器显然会浪费更多的CPU周期,但是它会降低程序的内存消耗总量,并可能因此减少分页。只有谨慎地测试才能给你最佳的参数值.
[1] 如果标准库提供一个用于对比两个子串的函数可能会是一个好主意,这样我们无需将子串解出(会创建新的字符串)即可检查字符串中的特定值.
[2] 缓存化,原文memoize 。
最后此篇关于Lua性能优化技巧(五):削减、重用和回收的文章就讲到这里了,如果你想了解更多关于Lua性能优化技巧(五):削减、重用和回收的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在构建一个我想要的 FragmentPagerAdapter(带有小图标的那个); 到屏幕中间(水平)的第一个项目 滑动它并使它们向左/向右移动屏幕的五分之一 实现此目标的最佳方法是什么? 这是一
我正在使用 GalleryView 和大约 40 张图片,而且速度很慢,因为没有回收... 任何人都可以向我展示在 getView 方法上对 GalleryView 的基本回收。 public cla
我收到警告 This FragmentManager should be recycled after use with #recycle() 我正在尝试修复它。有什么建议吗? date.setOnC
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 a specific programming problem, a software a
是否可以在 global.asax 中捕获回收事件? 我知道 Application_End 会被触发,但有没有办法知道它是由应用程序池的回收触发的? 谢谢,Lieven Cardoen 又名 Joh
当我第一次启动应用程序时,我以正确的方式获得了抽屉导航。当我向下滚动抽屉时,问题就出现了。元素开始消失,其中一些甚至交换了位置。我试图找出问题所在,但找不到。希望你能帮助我。 我已经使用 getIte
我正在尝试构建一个 Android 应用程序,在其中使用 RecyclerView。 在 RecyclerView 的项目中,我使用一个 TextView 和四个 CheckBox 来选择任何人。 现
回收 IIS7 应用程序池是否会终止任何当前正在执行的请求?还是等待所有请求完成(如排水管停止)? 我不希望回收规则导致我的 WCF 站点出现间歇性错误。 谢谢 最佳答案 不。 By default,
我动态创建 div,并希望通过检查 div 的 ID 以正确的顺序放置新的 div。 创建新数据时,我对数组进行排序并创建一个新的 div 容器。第一次构建 DOM 时,它工作正常,因为我先创建数据,
IIS 中 Web 应用程序的 .net Recycle 的 Java 等价物是什么。 这是在 IIS 之外的 Linux 机器上使用 Java 时的情况。 只是停止和启动应用程序吗? 最佳答案 并非
问题: 假设您的传输速度高达 10 MB/s,那么回收 DatagramPacket 对象(而不是每次发送数据包时创建一个新对象)是否是一个好主意? 故事: 我正在创建一个 LAN 文件同步应用程序,
我已经使用适配器创建了一个 ListView,但唯一的问题是我们使用了不同的布局,因为它是一个消息传递应用程序。我想通过使用 View 回收来提高性能,但不知道如何回收 View 。 是否可以更改 V
我是 Android 初学者,我不明白为什么会这样。 Activity 截图: 一切正常,除非我向下滚动(因此我认为它与回收有关)...所以当我向上滚动并尝试撤消第一篇文章中的投票(红色箭头)时,它认
我在 RecyclerView 中使用 FlexboxLayoutManager,我需要阻止 RV 回收。我尝试将 itemViewCacheSize() 设置为项目总数,但没有帮助。我也尝试将 ma
在我使用 SearchView 搜索项目后尝试从 RecyclerView 中删除项目时遇到问题,而如果我不使用 SearchView 并正常删除该项目,它工作正常。 这是一个示例,我正在删除该项目,
我正在尝试动态更改 RecycleView 中的图像。它将成功更改但是当我滚动 RecycleView ImageView 时将更改 这是我的适配器类代码: public class Recycler
我有一个表格如下 |GroupID | UserID | -------------------- |1 | 1 | |1 | 2 | |1 |
大家好,在我的 Activity 布局中,我使用这个 XML 来获取按钮数组
我有一个动画时钟,目前有内存泄漏。我目前似乎能够将东西放在图像之上,但不能将其取走或必须清除它(除了重新绘制整个时钟以使秒针不在两个不同的位置之外)。 用于清除时钟组件的代码是: for(UIView
我正在尝试创建一个简单的动画,在 JavaFX 2.x 中将圆向左移动一个像素,该动画有效,但每当我尝试第二次启动时,它就不再起作用了。我尝试了几种方法,代码如下: public void handl
我是一名优秀的程序员,十分优秀!