您的位置:首页 > 移动开发 > Android开发

基础知识记录:OOM异常出现的情况与处理方式

2017-07-03 20:25 399 查看
1、 查询内存情况

:通过Android Studio的Memory Monitor查看内存中Dalvik Heap的实时变化

2、 异常出现的情况

:当之前分配的内存+新分配的内存超出系统分配的内存时即 getMemoryClass()获取到的内存数据时就超出了内存,出现OOM

3、 异常出现的原因

:1、无限循环;

2、加载的图片过大或者图片过多;

3、无限制创建各种对象;

4、等

4、 异常处理方法

:1、减少对象的使用,尽量使用轻量级的(使用更加轻量的数据结构、少使用静态与枚举等)

2、使用图片是可进行压缩(大小、质量压缩),使用3级缓存机制,使用LRU的机制来缓存处理好的Bitmap图片,减少内存的付出

3、listview与gridview、recyclerview等加载数据时,使用convertView进行复用。

4、一些系统自带的资源,尽量使用系统的,可以减小内存,也能减小apk的大小。

知识点:LRU机制

计算机中有一个概念,我们用缓存来存放以前读取的数据,而不是直接丢掉,这样,再次读取的时候,可以直接在缓存里面取,而不用再重新查找一遍,这样系统的反应能力会有很大提高。但是,当我们读取的个数特别大的时候,我们不可能把所有已经读取的数据都放在缓存里,毕竟内存大小是一定的,我们一般把最近常读取的放在缓存里(相当于我们把最近联系的朋友的姓名和电话放在大脑里一样)。现在,我们就来研究这样一种缓存机制。

LRU缓存利用了这样的一种思想。LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,也就是说,LRU缓存把最近最少使用的数据移除,让给最新读取的数据。而往往最常读取的,也是读取次数最多的,所以,利用LRU缓存,我们能够提高系统的performance.

实现:

要实现LRU缓存,我们首先要用到一个类 LinkedHashMap。 用这个类有两大好处:一是它本身已经实现了按照访问顺序的存储,也就是说,最近读取的会放在最前面,最最不常读取的会放在最后(当然,它也可以实现按照插入顺序存储)。第二,LinkedHashMap本身有一个方法用于判断是否需要移除最不常读取的数,

其中实现方式可使用双链表 + hashtable来实现

1.  public class LRUCache {
2.
3.      private int cacheSize;
4.      private Hashtable<Object, Entry> nodes;//缓存容器
5.      private int currentSize;
6.      private Entry first;//链表头
7.      private Entry last;//链表尾
8.
9.      public LRUCache(int i) {
10.         currentSize = 0;
11.         cacheSize = i;
12.         nodes = new Hashtable<Object, Entry>(i);//缓存容器
13.     }
14.
15.     /**
16.      * 获取缓存中对象,并把它放在最前面
17.      */
18.     public Entry get(Object key) {
19.         Entry node = nodes.get(key);
20.         if (node != null) {
21.             moveToHead(node);
22.             return node;
23.         } else {
24.             return null;
25.         }
26.     }
27.
28.     /**
29.      * 添加 entry到hashtable, 并把entry
30.      */
31.     public void put(Object key, Object value) {
32.         //先查看hashtable是否存在该entry, 如果存在,则只更新其value
33.         Entry node = nodes.get(key);
34.
35.         if (node == null) {
36.             //缓存容器是否已经超过大小.
37.             if (currentSize >= cacheSize) {
38.                 nodes.remove(last.key);
39.                 removeLast();
40.             } else {
41.                 currentSize++;
42.             }
43.             node = new Entry();
44.         }
45.         node.value = value;
46.         //将最新使用的节点放到链表头,表示最新使用的.
47.         moveToHead(node);
48.         nodes.put(key, node);
49.     }
50.
51.     /**
52.      * 将entry删除, 注意:删除操作只有在cache满了才会被执行
53.      */
54.     public void remove(Object key) {
55.         Entry node = nodes.get(key);
56.         //在链表中删除
57.         if (node != null) {
58.             if (node.prev != null) {
59.                 node.prev.next = node.next;
60.             }
61.             if (node.next != null) {
62.                 node.next.prev = node.prev;
63.             }
64.             if (last == node)
65.                 last = node.prev;
66.             if (first == node)
67.                 first = node.next;
68.         }
69.         //在hashtable中删除
70.         nodes.remove(key);
71.     }
72.
73.     /**
74.      * 删除链表尾部节点,即使用最后 使用的entry
75.      */
76.     private void removeLast() {
77.         //链表尾不为空,则将链表尾指向null. 删除连表尾(删除最少使用的缓存对象)
78.         if (last != null) {
79.             if (last.prev != null)
80.                 last.prev.next = null;
81.             else
82.                 first = null;
83.             last = last.prev;
84.         }
85.     }
86.
87.     /**
88.      * 移动到链表头,表示这个节点是最新使用过的
89.      */
90.     private void moveToHead(Entry node) {
91.         if (node == first)
92.             return;
93.         if (node.prev != null)
94.             node.prev.next = node.next;
95.         if (node.next != null)
96.             node.next.prev = node.prev;
97.         if (last == node)
98.             last = node.prev;
99.         if (first != null) {
100.                node.next = first;
101.                first.prev = node;
102.            }
103.            first = node;
104.            node.prev = null;
105.            if (last == null)
106.                last = first;
107.        }
108.        /*
109.         * 清空缓存
110.         */
111.        public void clear() {
112.            first = null;
113.            last = null;
114.            currentSize = 0;
115.        }
116.
117.    }
118.
119.    class Entry {
120.        Entry prev;//前一节点
121.        Entry next;//后一节点
122.        Object value;//值
123.        Object key;//键
124.    }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 基础