范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

作为Android开发,这个知识点一定要知道,官方也改了2次

  今天面试遇到同学说做过内存优化,于是我一般都会问那 Bitmap 的像素内存存在哪?大多数同学都回答在 java heap 里面,就比较尴尬,理论上你做内存优化,如果连图片这个内存大户内存存在哪都不清楚,实在不太能说得过去。
  Bitmap可以说是安卓里面最常见的内存消耗大户了,我们开发过程中遇到的oom问题很多都是由它引发的。谷歌官方也一直在迭代它的像素内存管理策略。从 Android 2.3.3以前的分配在native上,到2.3-7.1之间的分配在java堆上,又到8.0之后的回到native上。几度变迁,它的回收方法也在跟着变化。  一、Android 2.3.3以前
  2.3.3以前Bitmap的像素内存是分配在natvie上,而且不确定什么时候会被回收。根据 官方文档 的说法我们需要手动调用  Bitmap.recycle()   去回收:
  https://developer.android.com/topic/performance/graphics/manage-memory
  在 Android 2.3.3(API 级别 10)及更低版本上,位图的后备像素数据存储在本地内存中。它与存储在 Dalvik 堆中的位图本身是分开的。本地内存中的像素数据并不以可预测的方式释放,可能会导致应用短暂超出其内存限制并崩溃。
  在 Android 2.3.3(API 级别 10)及更低版本上,建议使用   recycle()   。如果您在应用中显示大量位图数据,则可能会遇到 OutOfMemoryError 错误。利用recycle()    方法,应用可以尽快回收内存。
  注意:只有当您确定位图已不再使用时才应该使用 recycle()。如果您调用recycle() 并在稍后尝试绘制位图,则会收到错误:"Canvas: trying to use a recycled bitmap"。二、Android 3.0~Android 7.1
  虽然3.0~7.1的版本Bitmp的像素内存是分配在java堆上的,但是实际是在natvie层进行decode的,而且会在native层创建一个c++的对象和java层的Bitmap对象进行关联。
  从BitmapFactory的源码我们可以看到它一路调用到 nativeDecodeStream   这个native方法:// BitmapFactory.java public static Bitmap decodeFile(String pathName, Options opts) {     ...     stream = new FileInputStream(pathName);     bm = decodeStream(stream, null, opts);     ...     return bm; }  public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {     ...     bm = decodeStreamInternal(is, outPadding, opts);     ...     return bm; }  private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {     ...     return nativeDecodeStream(is, tempStorage, outPadding, opts); }
  nativeDecodeStream   实际上会通过jni创建java堆的内存,然后读取io流解码图片将像素数据存到这个java堆内存里面:// BitmapFactory.cpp static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,         jobject padding, jobject options) {     ...     bitmap = doDecode(env, bufferedStream, padding, options);     ...     return bitmap; }  static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {     ...     // outputAllocator是像素内存的分配器,会在java堆上创建内存给像素数据,可以通过BitmapFactory.Options.inBitmap复用前一个bitmap像素内存     SkBitmap::Allocator* outputAllocator = (javaBitmap != NULL) ?             (SkBitmap::Allocator*)&recyclingAllocator : (SkBitmap::Allocator*)&javaAllocator;     ...     // 将内存分配器设置给解码器     decoder->setAllocator(outputAllocator);     ...     //解码     if (decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)                 != SkImageDecoder::kSuccess) {         return nullObjectReturn("decoder->decode returned false");     }     ...     return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(),             bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1); }  // Graphics.cpp jobject GraphicsJNI::createBitmap(JNIEnv* env, android::Bitmap* bitmap,         int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,         int density) {      // java层的Bitmap对象实际上是natvie层new出来的     // native层也会创建一个android::Bitmap对象与java层的Bitmap对象绑定     // bitmap->javaByteArray()代码bitmap的像素数据其实是存在java层的byte数组中     jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,             reinterpret_cast(bitmap), bitmap->javaByteArray(),             bitmap->width(), bitmap->height(), density, isMutable, isPremultiplied,             ninePatchChunk, ninePatchInsets);     ...     return obj; }
  我们可以看最后会调用 javaAllocator.getStorageObjAndReset()   创建一个android::Bitmap   类型的native层Bitmap对象,然后通过jni调用java层的Bitmap构造函数去创建java层的Bitmap对象,同时将native层的Bitmap对象保存到mNativePtr:// Bitmap.java // Convenience for JNI access private final long mNativePtr;  /**  * Private constructor that must received an already allocated native bitmap  * int (pointer).  */ // called from JNI Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,         boolean isMutable, boolean requestPremultiplied,         byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {     ...     mNativePtr = nativeBitmap;     ... }
  从上面的源码我们也能看出来,Bitmap的像素是存在java堆的,所以如果bitmap没有人使用了,垃圾回收器就能自动回收这块的内存,但是在native创建出来的nativeBitmap要怎么回收呢?从Bitmap的源码我们可以看到在Bitmap构造函数里面还会创建一个 BitmapFinalizer   去管理nativeBitmap:/**  * Private constructor that must received an already allocated native bitmap  * int (pointer).  */ // called from JNI Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,         boolean isMutable, boolean requestPremultiplied,         byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {     ...     mNativePtr = nativeBitmap;     mFinalizer = new BitmapFinalizer(nativeBitmap);     ... }
  BitmapFinalizer   的原理十分简单。Bitmap对象被销毁的时候BitmapFinalizer   也会同步被销毁,然后就可以在BitmapFinalizer.finalize()   里面销毁native层的nativeBitmap:private static class BitmapFinalizer {     private long mNativeBitmap;     ...     BitmapFinalizer(long nativeBitmap) {         mNativeBitmap = nativeBitmap;     }     ...     @Override     public void finalize() {         try {             super.finalize();         } catch (Throwable t) {             // Ignore         } finally {             setNativeAllocationByteCount(0);             nativeDestructor(mNativeBitmap);             mNativeBitmap = 0;         }     } }三、Android 8.0之后
  8.0以后像素内存又被放回了native上,所以依然需要在java层的Bitmap对象回收之后同步回收native的内存。
  虽然 BitmapFinalizer   同样可以实现,但是Java的finalize   方法实际上是不推荐使用的,所以谷歌也换了NativeAllocationRegistry   去实现:/**  * Private constructor that must received an already allocated native bitmap  * int (pointer).  */ // called from JNI Bitmap(long nativeBitmap, int width, int height, int density,         boolean isMutable, boolean requestPremultiplied,     ...     mNativePtr = nativeBitmap;     long nativeSize = NATIVE_ALLOCATION_SIZE + getAllocationByteCount();     NativeAllocationRegistry registry = new NativeAllocationRegistry(         Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), nativeSize);     registry.registerNativeAllocation(this, nativeBitmap); }
  NativeAllocationRegistry   底层实际上使用了sun.misc.Cleaner   ,可以为对象注册一个清理的Runnable。当对象内存被回收的时候jvm就会调用它。import sun.misc.Cleaner;  public Runnable registerNativeAllocation(Object referent, Allocator allocator) {     ...     CleanerThunk thunk = new CleanerThunk();     Cleaner cleaner = Cleaner.create(referent, thunk);     .. }  private class CleanerThunk implements Runnable {     ...     public void run() {         if (nativePtr != 0) {             applyFreeFunction(freeFunction, nativePtr);         }         registerNativeFree(size);     }     ... }
  这个Cleaner的原理也很暴力,首先它是一个虚引用, registerNativeAllocation   实际上创建了一个Bitmap的虚引用:// Cleaner.java public class Cleaner extends PhantomReference {     ...     public static Cleaner create(Object ob, Runnable thunk) {         ...         return add(new Cleaner(ob, thunk));     }     ...     private Cleaner(Object referent, Runnable thunk) {         super(referent, dummyQueue);         this.thunk = thunk;     }     ...     public void clean() {         ...         thunk.run();         ...     }     ... }
  虚引用的话我们都知道需要配合一个 ReferenceQueue   使用,当对象的引用被回收的时候,jvm就会将这个虚引用丢到ReferenceQueue   里面。而ReferenceQueue   在插入的时候居然通过instanceof   判断了下是不是Cleaner:// ReferenceQueue.java private boolean enqueueLocked(Reference<? extends T> r) {     ...     if (r instanceof Cleaner) {         Cleaner cl = (sun.misc.Cleaner) r;         cl.clean();         ...     }     ... }
  也就是说Bitmap对象被回收,就会触发Cleaner这个虚引用被丢入 ReferenceQueue   ,而ReferenceQueue   里面会判断丢进来的虚引用是不是Cleaner,如果是就调用Cleaner.clean()   方法。而clean   方法内部就会再去执行我们注册的清理的Runnable。最后
  在这里还分享一份由大佬亲自收录整理的学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料
  这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。
  当然,你也可以拿去查漏补缺,提升自身的竞争力。
  真心希望可以帮助到大家,Android路漫漫,共勉!
  如果你有需要的话,只需私信我【进阶】即可获取

魅族发布会新品提前曝光手机壳钢化膜镜纸中关村在线消息4月19日晚,魅族将举行春日新品观影会,潮玩品牌PANDAER智能家居品牌Lipro都有新品发布。18日下午,PANDAER官微对发布会上的新品做了提前曝光iPhon仅售1599元,6nm芯10G256G,荣耀再次发力了声明原创不易,禁止搬运,违者必究!现在的国内手机厂商,可以说是上得了厅堂,下得了厨房。不仅能够在中低端市场立足,还能够打造出高端旗舰机型,实现了大小通吃。没有过硬的技术,如何能够有软件更新P50Pro2。0。0。246发布说明(合入4月安全补丁)更新详情软件更新P50Pro2。0。0。246发布说明(合入4月安全补丁)感谢各位花粉的支持,欢迎您体验P50ProHarmonyOS2版本2。0。0。246。本次更新合入了安全补传三星电机参与苹果M2芯片研发,将供应FCBGA载板(ChinaIT。com讯)继M1芯片后,三星电子旗下三星电机(SamsungElectroMechanics)有机会和苹果(AAPLUS)再续前缘,为下一代M2芯片供应覆晶球闸阵iQOONeo6SE搭载80W快充红魔7Pro擎天柱定制版套装发布科技犬iQOONeo6SE马上也要来了。根据爆料,iQOONeo6SE将会搭载6。62英寸120HzOLED居中单孔屏,此外有标准的骁龙8704700mAh80W快充三件套。与上一一些奇奇怪怪的脑洞如我们所知,一维是一条线,二维是一个平面,三维是一个立体空间,那四维就是多个空间组成的平行时空吗?如果我们穿越到了另一个平行时空,是否会遇到那个时空的自己,那那个自己还是自己吗?平下降1000的旗舰手机,值不值得入手?传送直达httpsu。jd。comZI772GI中兴Axon30Ultra,12256GB版本,京东此款目前活动售价3898元,下单支付选择白条满999减25,到手价3873元,感井通科技快讯井通快讯庆祝庆祝庆祝最近大家看到企业支付宝的项目,搬家到了公链上面来了,就是信用建基的企业版支付平台。合作方航天信息下属爱信诺征信,潜在市场1700万企业用户,区块链基础的企业支付熬出头了?A53开启ColorOS12公测招募,系统升级就看绿厂系统更新在大众看来是一件喜闻见乐轻而易举的工作,其实不然,系统前期的开发耗时耗人力,到后期的维护更新,所需的工作量都是非常大的,周期性也很长,系统的推送工作,需要对应每一款机型进行终身学习是必需品也是稀缺品都大伟今天不仅是一个信息爆炸的时代,更是一个知识爆炸的时代。随着大数据物联网5G和人工智能的发展,今天的社会进入了学界所谓第四次工业革命的时代。前所未有的增量知识以愈来愈快的速度产媒体报道丨顺网科技打造虚拟世界元宇宙里永不落幕的ChinaJoy元宇宙经历一轮沉淀,一些浮沫已被市场撇去,有能力的优质企业开始寻求元宇宙概念与业务的融合,以寻求产业应用的加速落地。此前,顺网科技旗下品牌ChinaJoy宣布将推出MetaJoy元
想走得远,那就一群人走来源中国教育新闻网近年来,智慧教育行业发展的蓬勃趋势,不是所有老师都能感受和接受这样的潮流趋势。就比如现在的智慧课堂,以前试点建设班的老师依然是用智慧课堂来开展传统的授课,就好比穿10月多款5G新手机扎堆发布,这些新手机将不会再被淘汰10月国庆长假已经结束,手机企业又开始正常上班了,而上班之后当然就是发布新款5G手机了,由于中国移动要求自本月起所有新款手机都需要支持700MHz,也就是说这个月开始发布的手机将不小鹏汽车终身免费充电,享置换补贴小鹏P7作为小鹏第二代智能汽车,具备四个字方面的领先的能力P7的智能驾驶更适应中国本土化路况和驾驶习惯,具有高速自主导航驾驶和超级记忆泊车功能智能交互小P可实现一次唤醒多次对话随时iPhone13又被爆出3个BugiPhone13系列开售已经二十多天的时间了,iPhone13凭借着小刘海高刷屏更长的续航炫酷的电影模式更低的价格受到了不少用户的青睐,开售后销售异常火爆,官网订单排到11月份!即服务器行业近况解读会议纪要时间2021年10月10日星期日参会嘉宾资深服务器行业专家一嘉宾分享服务器行业近年发展情况早期,行业以传统服务器为主,阿里云腾讯云服务器出现后,公有云和传统服务器开始平分市场201超全支付宝隐藏功能,能帮你省下一个亿平时我们知道用支付宝付款,还不知道它能帮你省钱呢宝宝们注意啦,其实支付宝用的好可以省很多钱s哦!今天甜泡就来分享一下那些你不知道的支付宝功能。1。免费优惠券打开支付宝首页搜素715微信上可以交社保了,你知道吗?快来看看之前我们介绍了在支付宝里交社保的方法步骤,有人反映自己很少用支付宝,其实用微信也是可以的。具体步骤如下第一,打开微信,点击下方最右侧我的按钮。第二,点击支付,在新界面中有生活服务分OPPOReno7入网信息曝光,搭载IMX766主摄,相机采用全新造型旗舰机半年迭代现在属于正常情况,但是一个系列做到一年更新三代,可能只有OPPOReno系列了。距离OPPORneo6系列发布还不到半年的时间,现在Reno7系列的各种爆料和认证也安如果是阿里巴巴收购了Foxmail,张小龙在阿里也能做出微信来吗?不能!我一直说,张小龙作为一个独立写出Foxmail前三个版本的产品经理程序员,他无疑是中国最成功的产品经理!张小龙的名字下有三个响当当的产品,Foxmail,QQ邮箱,微信!尤其外媒续航实测iPhone13ProMax进步显著,安卓这款机型表现最好作为苹果的最新年度旗舰,iPhone13系列从即将发布到已发布,受到的关注度一直都是有增无减。而此次iPhone13系列最明显的升级点,除了A15芯片以外,就是把屏幕刷新率提到了1百亿补贴重新上架!iPhone13再次贬值,你买早了吗?对iPhone比较关注的朋友,打算买iPhone的时候都应该听说过百亿补贴这个词,虽然这是电商平台用来吸引用户的广告,但现在已经成为暗指针对新iPhone的补贴。百亿补贴最开始是从