内存抖动:短时间内大量对象被创建,然后又被释放,这种情况如果达到内存的阈值会触发GC
内存泄漏:一些不再使用的垃圾对象,由于引用了还在使用的对象,导致不能被回收,这些垃圾对象多了,就会导致oom。
以上三者,内存溢出最需要注意、内存泄漏次之,内存抖动最后。
3、如何解决oom
3.1有关bitmap
图片显示:加载合适大小的图片,不要总是请求网络大图,有时可以使用缩略图。
及时释放内存
图片压缩
捕获异常
3.2其他方面
listview:convertview/lru
避免在onDraw方法里面执行对象的创建(如果在onDraw方法里面频繁地进行对象的创建,会造成内存突然上升,而在释放这些内存的时候,又会造成频繁地GC,这样就导致内存抖动)
谨慎使用多进程
三、Bitmap
========
1、recycle
public final class Bitmap implements Parcelable {
/**
-
Free the native object associated with this bitmap, and clear the
-
reference to the pixel data. This will not free the pixel data synchronously;
-
it simply allows it to be garbage collected if there are no other references.
-
The bitmap is marked as “dead”, meaning it will throw an exception if
-
getPixels() or setPixels() is called, and will draw nothing. This operation
-
cannot be reversed, so it should only be called if you are sure there are no
-
further uses for the bitmap. This is an advanced call, and normally need
-
not be called, since the normal GC process will free up this memory when
-
there are no more references to this bitmap.
*/
public void recycle() {
if (!mRecycled && mNativePtr != 0) {
if (nativeRecycle(mNativePtr)) {
// return value indicates whether native pixel object was actually recycled.
// false indicates that it is still in use at the native level and these
// objects should not be collected now. They will be collected later when the
// Bitmap itself is collected.
mNinePatchChunk = null;
}
mRecycled = true;
}
}
}
在源码中的注释:
该方法用于释放跟这个bitmap(位图)有关的native(本地)对象,并清除跟数据对象有关的reference(引用)。
但是这个方法并不会同步立即清除数据对象,系统会给垃圾回收机制(GC发送指令),如果GC发现这些数据没有
其他的引用的话,就会回收这些数据对象。
调用该方法后,该bitmap会被标记为"dead",因此任何调用它的方法都会报异常。
这个操作不可逆,所以一定要确保该位图没有被调用时,再谨慎地调用该方法。
该方法,一般不建议调用,因为改位图如果没有引用的情况下,会自动被GC回收。
2、LRU
package android.support.v4.util;
public class LruCache<K, V> {
private final LinkedHashMap<K, V> map;
public final V get(K key) {…}
public final V put(K key, V value) {…}
public void trimToSize(int maxSize) {…}
}
LruCache算法(Least Recently Used),也叫近期最少使用算法。它的主要算法原理就是把最近使用的对象用强引用存储在LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。
相关文章:Android高效加载大图、多图解决方案,有效避免程序OOM
面试题:LRU算法是怎么实现的?
它的内部是用一个LinkedHashMap来实现的,里面提供了一个get、put方法来完成缓存的获取和添加。当缓存满的时候,它会提供一个trimToSize方法,把已添加的时间最长的缓存清除,添加新的缓存对象。
接下来我们看这个trimToSize方法:
/**
-
Remove the eldest entries until the total of remaining entries is at or
-
below the requested size.
-
@param maxSize the maximum size of the cache before returning. May be -1
-
to evict even 0-sized elements.
*/
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
- “.sizeOf() is reporting inconsistent results!”);
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
3、计算inSampleSize
// 根据maxWidth, maxHeight计算最合适的inSampleSize
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
4、缩略图
//缩略图
public static Bitmap thumbnail(String path,
int maxWidth, int maxHeight, boolean autoRotate) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 获取这个图片的宽和高信息到options中, 此时返回bm为空
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false;
// 计算缩放比
int sampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inPurgeable = true;
options.inInputShareable = true;
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
5、三级缓存
网络缓存、本地缓存、内存缓存
当我们的APP首次请求一张图片时,会从网络中获取,当这张图片加载成功之后,这张bitmap会被保存在内存和本地文件中各一份,当我们再次请求这张同样地址的图片时,就直接从内存或者本地文件中获取,避免再次从网络中获取,减少流量消耗。
6、BitmapUtils.java
public class BitmapUtils {
// 根据maxWidth, maxHeight计算最合适的inSampleSize
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
//缩略图
public static Bitmap thumbnail(String path,
int maxWidth, int maxHeight, boolean autoRotate) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 获取这个图片的宽和高信息到options中, 此时返回bm为空
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false;
// 计算缩放比
int sampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inPurgeable = true;
options.inInputShareable = true;
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
//保存bitmap
public static String save(Bitmap bitmap,
Bitmap.CompressFormat format, int quality, File destFile) {
try {
FileOutputStream out = new FileOutputStream(destFile);
if (bitmap.compress(format, quality, out)) {
out.flush();
out.close();
}
if (bitmap != null && !bitmap.isRecycled()) {
文末
面试:如果不准备充分的面试,完全是浪费时间,更是对自己的不负责!
不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!