① android中怎么防止oom
内存泄露的原因:
1. Handler造成内存泄漏
private Handler handler = new Handler(){
@Override
public void handMessage(Message msg){
}
}
当使用内部类(包括匿名类)来创建Handler时,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用。
而Handler通常会伴随一个耗时的后台线程(例如访问网络或者从网络上拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完成)之后,通过消息机制通知Handler,然后Handler把图片更新到界面上(主线程中)。
当用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉。但是由于这时线程尚未执行完,而该线程持有Handler的引用,Handler持有Activity的引用,就导致Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完成)。
另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue —> Message —> Handler —> Activity的链,导致你的Activity被持有引用而无法被回收。
使用Handler导致内存泄露的解决办法:
一、通过程序逻辑进行保护
A. 在finish Activity的时候停掉你的后台线程,线程停掉了,就相当于切断了Handler与外部连接的线,Activity自然会在合适的时候被回收。
B. 如果Handler被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列中移除即可。
二、将Handler声明为静态类
静态类不持有外部类的引用对象,所以Activity可以随意被回收。
static class MyHandler extends Handler{
@Override
public void handleMessage(Message msg){
}
}
此时由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)
static class MyHandler extends Handler{
WeakReference<Activity> activityReference;
public MyHandler(Activity activity){
activityReference = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg){
final Activity activity = activityReference.get();
}
}
对应以上的代码,用户在关闭Activity之后,就算后台线程还没结束,但由于仅有一条来自Handler的弱引用指向Activity,所以GC仍然会在检查的时候把Activity回收掉。
So, 关于Handler内存泄露的问题就不会出现。
② android何时会发生oom怎么解决oom
首先,OOM就是内存溢出,即Out Of Memory。也就是说内存占有量超过了VM所分配的最大。
怎么解决OOM,通常OOM都发生在需要用到大量内存的情况下(创建或解析Bitmap,分配特大的数组等),在这样的一种情况下,就可能出现OOM,据我现在了解到,多数OOM都是因为Bitmap太大。所以,这里我就专门针对如何解决Bitmap的OOM。其实最核发的就是只加载可见范围内的Bitmap,试想这样一种情况,在GridView或ListView中,数据量有5000,每一屏只显示20个元素,那么不可见的,我们是不需要保存Bitmap在内在中的。所以我们就是只把那么可见的Bitmap保留在内存中,那些不可见的,就释放掉。当元素滑出来时,再去加载Bitmap。
这里我有两种方式,都可以避免OOM。
③ oom如何解决和预防
尽量提高自己的免疫力,然后不断的锻炼身体,这样的话对于预防来说是有很好的疗效。
但是我们还需要掌握一定的方式方法。
④ 怎么解决oom android
如果是第一次创建的时候就出错,那试试在创建bitmap的时候不要把public static Bitmap createBitmap (int width, int height, Bitmap.Config config)的第三个参数写成ARGB_8888,换成其他的值。
如果是多次创建的时候才OOM,那么一定要想办法,在合适的地方,对你已经创建的bitmap进行recycle操作。
⑤ android使用全局的dialogview怎样避免oom
避免OOM的第一步就是要尽量减少新分配出来的对象占用内存的大小,尽量使用更加轻量的对象。
1)使用更加轻量的数据结构
1、考虑使用ArrayMap/SparseArray(SparseBoolMap,SparseIntMap,SparseLongMap,LongSparseMap)而不是HashMap等传统数据结构
ArrayMap、SparseArray使用场景:
对象个数的数量级最好是千以内
数据组织形式包含Map结构
⑥ android oom问题 如何避免
ROM有什么问题,你是否能说一下,如果你说的是有些人不断地刷ROM,那不过是他们的兴趣罢了,没有最好的ROM,而那些刷机不断地人则是在找更好的ROM,你如果觉得你的ROM可以忍受,你就不用刷,如果你想试一试新的系统,你就可以刷一下不同的ROM,其实ROM对手机的性能影响还是挺大的,一个好的ROM可以使你的手机更省电,CPU主频更高,你要不要刷,自己看着办把。
说了这么多,我都觉得自己说的挺乱的,如果你有什么问题,接着问吧
⑦ android图片压缩避免OOM
简单吹下牛:很多app都会要加载图片,但是如果不压缩图片就很容易OOM,
个人看来OOM 出现原因总的来说分为两种:
一种是内存溢出(好像在扯淡,OOM本身就是内存溢出)
另一种是:图片过大,一个屏幕显示不完全造成,似乎也是一。。 如有错误纯属扯淡;
为了避免上面的情况:加载图片的时候可以进行压缩,上传的时候要可以进行压缩,在图片不可见的时候进行回收(onDetach()),再吹一句 用了fresco+压缩之后加载图片完全没问题了。
一、质量压缩方法:
privateBitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos =newByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG,100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
intoptions =100;
while( baos.toByteArray().length /1024>100) {//循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
options -=10;//每次都减少10
}
ByteArrayInputStream isBm =newByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm,null,null);//把ByteArrayInputStream数据生成图片
returnbitmap;
}
二、图片按比例大小压缩方法(根据Bitmap图片压缩)
privateBitmap comp(Bitmap image) {
ByteArrayOutputStream baos =newByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG,100, baos);
if( baos.toByteArray().length /1024>1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG,50, baos);//这里压缩50%,把压缩后的数据存放到baos中
}
ByteArrayInputStream isBm =newByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options newOpts =newBitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds =true;
Bitmap bitmap = BitmapFactory.decodeStream(isBm,null, newOpts);
newOpts.inJustDecodeBounds =false;
intw = newOpts.outWidth;
inth = newOpts.outHeight;
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
floathh = 800f;//这里设置高度为800f
floatww = 480f;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
intbe =1;//be=1表示不缩放
if(w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
}elseif(w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if(be <=0)
be =1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
isBm =newByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm,null, newOpts);
returncompressImage(bitmap);//压缩好比例大小后再进行质量压缩
}
⑧ android开发内存优化之如何有效避免oom
减小对象的内存占用
内存对象的重复利用
避免对象的内存泄露
内存使用策略优化
设计风格很大程度上会影响到程序的内存与性能,相对来说,如果大量使用类似Material Design的风格,不仅安装包可以变小,还可以减少内存的占用,渲染性能与加载性能都会有一定的提升。
内存优化并不就是说程序占用的内存越少就越好,如果因为想要保持更低的内存占用,而频繁触发执行gc操作,在某种程度上反而会导致应用性能整体有所下降,这里需要综合考虑做一定的权衡。
Android的内存优化涉及的知识面还有很多:内存管理的细节,垃圾回收的工作原理,如何查找内存泄漏等等都可以展开讲很多。OOM是内存优化当中比较突出的一点,尽量减少OOM的概率对内存优化有着很大的意义。
⑨ Android Bitmap 内存以及OOM问题讨论
都知道在Android中, 每个应用所使用的内存是有限的,现在的手机通常最大的内存使用为256M, 目前还没发现Android中一个应用的最大内存分配超过256M的(经测试华为手机的最大内存是385M)
相关API:
ActivityManager.getMemoryClass(),首先获取系统服务中的ActivityManager
如下:
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
可以获取到相关信息
最近一直被项目的OOM问题困扰, 在网上查阅相关资料,前前后后读了不下于30篇,这些篇幅讲解的东西都是千篇一律,并没有解决到实际问题
也在慕课网学习了内存优化章节
这是慕课网讲师的PPT,我截屏的
这里来仔细分析一下:
第一个, 注意临时Bitmap对象的及时回收, 来看下相关API
直接上图
经过我无数次的使用Android studio工具自带的MAT分析工具后, 得出一个很严谨的结论, 此方法并不奏效...
Android中Bitmap的内存存放在堆区, Google 的Bitmap的recycle方法注释也可以了解到
Android历史版本不是很清楚, 据说Android3.0之前Bitmap是存放在native区域,可以进行手动释放,然而3.0之后Bitmap是存放在Java层的堆区,没错是heap, 内存管理直接交由系统GC管理,你还这样释放资源有意义?无非是给自己的一点心理安慰罢了, 告诉你没卵用
又有人在说要释放内存使用System.gc() ??? 对就是主动触发垃圾回收,这个API是开发者自行调用的吗?那么系统管理内存还有什么意义?这不是误人子弟吗,这个API不能调用的, 因为没卵用的, 具体自己参照MAT工具自行分析.即便垃圾回收真的被触发了, 所有线程停滞由系统来清理垃圾, 造成的后果是严重卡顿!!!
再看一个API:
我在网上苦苦追寻内存过高的问题后,发现了这个API,经过无数次实践后我得出一个结论,没卵用...开发者可以抛弃它
综上所诉, 第一点讲解的内存优化问题可以直接PASS掉, 无非给自己一点心理安慰: 我已经处理好了内存问题, 程序不会OOM?
第二点. 避免Bitmap的浪费
直接说结论, 这个是非常行之有效的,并且是一定能解决问题的
具体怎么操作呢? 自己实现LruCache这个类, 就是这么弄, 原理就是解码复用, 在内存中已经解码好的Bitmap直接拿出来使用, 没有的在加载到内存进行解析, 这个非常有效,但是并不能让你避免OOM
第三点, try-catch某些大内存分配的操作
这点上,我又要开始疑问了, 我Java功底不是很好
Java中发生内存溢出时,抛出的是OutOfMemoryError, 它的父类是VirtualMachineError
这玩意能catch住? 它属于Error范畴, 你能捕获?请Java大神出来说一下,我解释不清楚
第四点, 加载Bitmap 缩放比例, 解码格式, 局部加载
先来分析一下缩放比例:
按照市面上主流的手机分辨率来分析现在Android主流的分辨率是1920X1080, 如果一个ImageView控件刚好就是屏幕全屏,怎么说?直接占用掉8M内存, 想想一个实际的需求情况
一个查看大图的页面, 不断的关闭,打开查看新的大图,问题就来了,内存一直在暴增,迟早会突破界限OOM掉
分辨率是2K屏呢? 更恐怖了, 随着手机设备的屏幕分辨率提升, 加载图像需要的内存也是倍增的, 因为应用的最大内存并没有增加
结论: 缩放比例可以有效的降低内存占用问题, 但不是绝对的救命稻草, 该缩放的还是要缩放,而且必须缩放,就是采样 现在通常都是图片加载框架来完成,类似Glide.Picasso,Fresco等,他们可以帮助你减少工作量, 内存问题还是存在
再来分析一下解码格式:
这个跟缩放比例效果差不多, 只是同样的分辨率的图片加载到内存中时占用内存减少了
比如ARGB_8888 共32位
RGB_565 共16位
ARGB_4444 共16位
很明显这样格式图片加载的内存情况是ARGB_8888是其他格式的两倍内存
另外的问题是ARGB_8888看起来很清晰的, 其它的看起来图片有种糊了的感觉,自己选择吧
结论, 降低内存占用非常有效
最后一个是局部加载, 并没有怎么使用到,也不清楚就不说了
最后还有一个方法避免OOM, 开启largeHeap属性, 但是但是, 以前我们开启这个属性后被Oppo应用市场认定为占用内存过高, 不建议用户安装......所以我们又取消了!
总的来说, Bitmap在内存是变现的是不可控, 我项目OOM问题一直没有得到有效解决,因为图片编辑视频编辑之类的功能占用内存过高,继续使用OOM是必然的, 跟IOS的同学交流了一番,他们说IOS的应用内存可以占用到1个G以上, 轻松跑到500M是没问题的, IOS的内存机制可以持续给内存使用, 具体我也不清楚,并且他们可以手动释放内存?malloc, free这样子?
如果大家有比较好的方案,还望留言交流互相帮助 [笑脸.gif]
补充: Android8.0开始Bitmap数据内存存在native层, 单个应用可用的内存显着增长, 极大的降低了OOM的概率(2018年3月22日)