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. }