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

作为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路漫漫,共勉!
  如果你有需要的话,只需私信我【进阶】即可获取

健合集团第六届中国特殊食品大会,主办益生菌营养健康高峰论坛为探讨产业创新之道,助推行业变革,2021年10月1518日,2021第六届中国特殊食品大会在江苏无锡隆重召开。健合集团作为全球高端营养及健康产业领导者,携旗下合生元Swisse斯Soul教你甩掉社恐露营式社交或将成为新热潮2021年最后一个长假已经结束,在今年所有假期里享有高人气的娱乐项目便是露营。露营已经成为95后假期娱乐的首选,其中露营式社交也为Ta们开启了新的社交世界。此前,Soul发布了20为你全方位解答拍拍贷利息到底多高拍拍贷用户人群包含甚广,其中不乏年轻人。对于刚步入社会的毕业一族来说,网络借款可谓是沙漠里的一缕清泉,为他们提供初入社会的消费保障。现如今人们先消费后付款的习惯,是的我们总是囊中羞Soul全面开展打击杀猪盘行动风控体系升级提供坚实后盾10月11日至17日,2021年国家网络安全宣传周在全国范围内统一举办,法治日电信日青少年日在内的众多主题活动圆满落幕。Soul作为一款正能量的人气社交应用,积极响应并参与到了网络第三届(江西)国际通信电子产业博览会,UampampampI由我诚邀您观展2020年中国国际通信电子产业博览会(ChinaInternationalCommunicationElectronicsIndustryEXPO)即将在2020年10月18日20玛莎拉蒂推出品牌首部油电动车款GhibliHybrid,48V轻油电动力MASERATI推出品牌首部油电动车款GhibliHybrid,结合48V轻油电动力技术再不来电,事情就大条了!可能会因为碳排放过量被罚,更有可能人气会大幅缩水。就在FCA在与PS保时捷718CaymanGT4试驾笑看弯道的街道赛车保时捷718CaymanGT4试驾笑看弯道的街道赛车跑车有很多种,有的为了挑战极速而生有的视赛道为归属,不同种类各有所长,当然也有擅长在弯道中展现驾驭魅力的跑车,而保时捷718Ca奔驰GLA200鲜明休旅风格好开至上奔驰GLA200试驾鲜明休旅风格好开至上奔驰旗下的入门车系NewGenerationCompactCars(后简称NGCC),是品牌面对全新市场需求制定的车系策略,主要透过模块化平疯狂野马是你!采七具电动马达的福特MustangMachE1400登场疯狂野马是你!采七具电动马达的MustangMachE1400登场!FordMustangMachE虽挂着野马名号却是一台不折不扣的电动休旅,上市以来一直是同级距中的话题焦点,虽然能跟特斯拉掰手腕的,只有保时捷了能跟特斯拉掰手腕的,只有保时捷了竞争,拼的不只是才华,还有底蕴。在特斯拉站在电动汽车塔尖俯瞰群雄,嘲笑传统的时候。日内瓦车展上,保时捷推出一款新品电动汽车MissionECross被指抄袭!WEY全新SUV将成为中国版FORDBronco?被指抄袭!WEY全新SUV将成为中国版FORDBronco?国内市场虽大,但抄袭剽窃的情事却是不停的发生,甚至有些知识产权官司原创反而有可能在国内市场败诉。而国内车市过往同样也是抄
机器人四大巨头业绩下滑?国产的春天要来了2019年,是一个拐点。ABB发那科安川和KUKA财年业绩出现了不同程度的下滑发那科2018Q4营收同比下滑19。80,连续4季度下滑ABB2019Q1收入营业利润同比降低6安川电这个采摘水果的机器人,手速比农民快多了每到丰收的季节,英国的果农往往十分烦恼。不是担心这些农作物滞销,而是请不到人来采摘这些成熟的果实。现在,机器人正在接管这项乏味的工作,而且做的比人类好多了。英国普利茅斯大学的研究机盘点江苏省工业机器人产业头角崭露,爆发在即在未来,机器人是否会取代人类的工作?这个话题近几年备受关注,伴随着5G人工智能等技术的发展,让机器人真正走进了人们的生活,有了更深的认知,甚至有了威胁意识,其实这是一个好事,起码机2020年中国协作机器人行业市场现状与竞争格局分析协作机器人是一种被设计成能与人类在共同工作空间中进行近距离互动的机器人。协作机器人是工业机器人的一类,顾名思义是指用于同人类工人一起协作。一2019年我国协作机器人市场规模约为13日本机器人是如何与苏联打赢竞赛,在50年内做成完美体系的?在贸易战的当下,特朗普首次登日本战舰,我们不由得会去思考,日本机器人企业是否会受到政治冲击?这对于国内企业到底是机遇还是挑战?说到日本,也许再没有一个国家像日本这样广泛的制造与运用男子国庆深夜突发心梗,险些离世!所有的突如其来,都是蓄谋已久国庆假期第一天天,29岁王先生和朋友吃火锅喝啤酒到深夜,这样的聚餐,对他来说,其实平时也非常频繁。但没想到回家睡觉后,在凌晨2点的时候,突然感觉胸痛得厉害,而且呼吸困难,大汗淋漓。冠心病天天喝三七粉泡水,这5个问题一定要搞清楚中药三七的药理作用较多,具有止血补血抗血栓消肿镇痛保肝利胆的功效,是人们熟知的一种中药材。本草纲目认为,三七的根具有消肿镇痛散瘀的功效。所以很多冠心病患者会将三七根磨成粉泡水喝,来60岁以后,如何延缓衰老,提升生命质量?做好这4方面很重要对人类而言,衰老是一个缓慢出现必然发生的生物学过程,可表现为皮肤皱纹头发花白行动迟缓记忆功能减退等。有人问,60岁以后,如何延缓衰老,提升生命质量?首先我们需要清楚一点,衰老是一个新药非奈利酮获批上市!糖尿病肾病有了新选择,不仅保肾还能护心刚工作时,常常会听到前辈反复说着一句话糖尿病并不可怕,可怕的是糖尿病的并发症。没错,如今一眨眼十几年过去了,对这句话深有体会,尤其是遇到太多的糖尿病肾病的患者,许多患者甚至需要终身降压药降脂药一盒才7片,为何不用大包装?专家说出背后的原因很多高血压高血脂患者发现,这些降压药调脂药大多采用的是7片一盒的包装。很多慢性病患者认为,这种7片一盒的包装是过度包装,增加成本,而且造成极大的浪费,不利于环保,更重要的是不利于保去澳门吃什么?除了玛嘉烈蛋挞,还有这些不可错过的美食澳门除了赌场大三巴及蛋挞,还有许多让你惊喜的美食!在这个适合短期旅行的地方,如果你经过某一家阿宝推荐的店铺,一定要排队进去尝一尝哦李康记豆腐花夏季消暑的好选择,豆腐花绵密嫩滑,入口