内存受限下的设计模式(4)——欧茨队长
背景
先讲个故事。
欧茨队长是维多利亚女王时代的一位探险家。在去往南极的探险之旅的返程中,探险队出现补给短缺情况。心情沮丧又患了冻疮的欧茨为了给其他队员创造生存机会,牺牲了自己。他走进暴风雪中,留下了知名的一页日记:“I just going outside and may be some time.”(我出去转转,可能得一会儿)。然而,欧茨的牺牲并没有挽救他的队伍。次年他们的遗骸被发现。
模式
欧茨队长模式要求我们应该牺牲非必要组件的内存,以满足更重要的任务的内存需求。
更深入的讨论
欧茨队长知道现在团队的补给严重短缺,所以他选择牺牲了自己。那么我们的“欧茨组件”何时能够知晓系统中可用内存短缺这个信息呢?通常有两种方式:
操作系统广播内存不足消息;操作系统提供内存状态查询的接口,每个组件负责轮询系统内存情况来确定内存不足。
然而,该模式会在组件间引入耦合。同时,释放资源本身也是一个费时的操作(java程序员大概都知道不要显式地去调用System.gc(),道理是一样的)。
最后,实现该模式需要一个具有良好编程素养的团队。毕竟,释放内存的组件肯定是系统中不重要的模块,但是绝少有程序员愿意承认自己编写的组件是次要的。这也解释了为什么欧茨队长那么伟大——绝少有人自愿为他人放弃生命。
实现
内存可用量很低时,许多操作系统都会发布事件用以警告应用程序。windowsCE会向所有窗口送出WM_COMPACTING和WM_HIBERNATE消息,警告他们内存数量正在降低。
另一种方式是系统提供一个函数以显示当前内存总量。组件负责轮询。如果内存总量很低,就释放内存。比如在java.lang.Runtime中的freeMemory()函数可以返回当前JVM可用的内存数量,以字节为单位。
示例
以下是android检测系统内存是否过低的方法:
private static boolean isLowMemory(Context context) { if (null == context) { return false; } ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo(); am.getMemoryInfo(outInfo); return outInfo.lowMemory; }