版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
NDK高频面试题及详细实战答案一、NDK基础认知类1、说说NDK是什么,日常开发中主要用来解决什么问题?参考答案:NDK是安卓原生开发工具包,是一套可以让Android应用调用C/C++代码的编译、工具、链接库集合。日常开发核心用途主要有四点:第一,性能优化。图片处理、音视频编解码、大数据运算、加密解密等耗时操作,用C/C++实现,比Java纯代码效率更高,避免Java虚拟机卡顿、GC抖动问题。第二,代码复用。跨平台C/C++库可以直接复用,不用Android、iOS分别写一套逻辑,比如人脸识别、算法、推流、播放器内核。第三,安全加固。核心业务逻辑、密钥、算法放在原生层,相比Java代码更难被反编译、篡改,提升应用安全性。第四,底层能力调用。可以直接调用Linux底层API、硬件相关能力,弥补Java层底层权限和能力的不足。2、JNI和NDK的区别是什么?参考答案:很多人会混淆两者,其实分工完全不同:JNI是一套通信协议/接口标准。全称Java原生接口,是Java虚拟机定义的一套规范,用来实现Java层和C/C++原生层的相互调用,定义了数据类型映射、函数调用规则、对象操作规则,属于接口规范。NDK是一套开发工具集合。包含编译器、链接器、交叉编译工具、平台库、头文件、打包工具,是用来编译、构建、运行原生代码的工具链,属于开发工具。简单总结:JNI是通信规则,NDK是干活的工具,我们通过NDK工具,按照JNI规范实现原生开发。3、Android目前主流的NDK构建方式有哪些?区别是什么?参考答案:主流两种:Android.mk+Application.mk、CMakeLists.txt1、mk构建:是早期AndroidNDK的构建方式,语法简洁、适合简单项目、单库编译。缺点是兼容性差、不支持增量编译、复杂多模块项目维护困难,谷歌已经不再主推,仅老旧项目使用。2、CMake构建:目前官方主推方式,适配新版AndroidStudio,支持增量编译、多模块管理、跨平台配置,语法通用、可读性高,支持灵活配置编译参数、依赖库、架构过滤,新项目基本全部使用CMake。4、NDK支持哪些CPU架构?项目中一般怎么配置适配?参考答案:常见架构:armeabi-v7a、arm64-v8a、x86、x86_641、armeabi-v7a:32位ARM架构,适配老旧安卓设备,兼容性最广,目前新机基本淘汰;2、arm64-v8a:64位ARM架构,主流手机设备,性能最好、是项目必配架构;3、x86/x86_64:适配模拟器、电脑端安卓模拟器,真机设备极少使用;项目常规配置:正式打包只保留arm64-v8a+armeabi-v7a,减小包体积;调试阶段可开启x86方便模拟器调试。二、JNI核心原理与调用类1、JNI中Java与C/C++的数据类型映射关系?基本类型和引用类型区别?参考答案:基本数据类型是直接映射、值传递,无需手动释放:jboolean、jbyte、jchar、jshort、jint、jlong、jfloat、jdouble分别对应Java基础八大类型。引用类型是指针映射、地址传递,需要手动管理引用,否则会内存泄漏:jstring对应String、jobject对应普通对象、jarray对应数组、jclass对应类对象。核心区别:基本类型直接拷贝值,无内存风险;引用类型是JVM对象的指针,原生层持有后会影响JVM垃圾回收,必须手动释放局部引用、全局引用。2、JNI中局部引用、全局引用、弱全局引用的区别及使用场景?参考答案:1、局部引用(LocalReference)默认创建的引用,生命周期仅限当前JNI方法调用期间,方法执行结束后自动失效。特点:数量有限(默认上限512),不能跨线程、不能跨方法使用。场景:方法内临时使用的字符串、数组、对象,使用完必须DeleteLocalRef,避免局部引用溢出。2、全局引用(GlobalReference)通过NewGlobalRef创建,生命周期贯穿整个应用进程,手动创建、手动释放。特点:可以跨线程、跨方法使用,会阻止JVM对象回收,不释放会严重内存泄漏。场景:全局缓存的Java对象、回调接口、工具类实例。3、弱全局引用(WeakGlobalReference)通过NewWeakGlobalRef创建,不会阻止JVM垃圾回收,对象被回收后引用自动失效。场景:缓存非必须存活的对象,避免全局引用导致的内存常驻,使用前需要判空。3、JNI中调用Java静态方法和实例方法的流程?参考答案:通用四步流程:1、通过FindClass获取Java类的class对象;2、通过GetMethodID/GetStaticMethodID获取方法ID(需要方法签名);3、调用对应Call方法:实例方法用CallVoidMethod/CallIntMethod等,静态方法用CallStaticVoidMethod等;4、释放局部引用,避免内存泄漏。核心区别:静态方法依赖class对象即可调用,实例方法必须依赖具体的对象实例,不能直接通过class调用。4、JNI方法签名的作用?常见签名格式有哪些?参考答案:JNI无法直接通过方法名匹配重载方法,必须依靠方法签名区分重载、同名不同参数的方法,保证调用精准。常见基础签名:I:int、Z:boolean、V:void、J:long、F:float、D:double、C:char、B:byte对象格式:L包名/类名;例如String是Ljava/lang/String;数组格式:[+类型例如int[]是[I,String[]是[Ljava/lang/String;整体格式:(参数签名)返回值签名,例如voidtest(inta)签名为(I)V。三、JNI内存管理与常见坑点1、GetStringChars/GetStringUTFChars区别?使用后为什么必须释放?参考答案:1、GetStringChars:获取Unicode编码字符串,宽字符wchar_t,适合中文、特殊字符,占用内存更大;2、GetStringUTFChars:获取UTF-8编码字符串,单字节/多字节,是开发最常用的格式,适配绝大多数业务场景。必须释放的原因:这两个方法会拷贝JVM字符串数据到原生层内存,或者锁定JVM内存,如果不调用Release方法释放,会造成内存泄漏、JVM内存锁定,导致GC无法回收内存,长期运行会引发OOM。2、JNI开发中常见的内存泄漏场景有哪些?参考答案:1、局部引用未释放:循环中频繁创建jstring、jobject,不执行DeleteLocalRef,导致局部引用溢出、内存堆积;2、全局引用未释放:Activity、回调接口、View等对象被全局引用持有,页面销毁后无法回收,造成页面内存泄漏;3、字符串、数组未释放:GetString、GetArray系列方法使用完不Release,内存常驻;4、原生层开启线程持有Java对象,线程不退出、对象不释放;5、动态注册的JNI方法未反注册,导致类引用常驻内存。3、什么是JNI局部引用溢出?如何解决?参考答案:JNI单个方法的局部引用有数量上限,默认512个。如果在循环中不停创建jobject、jstring且不及时释放,会超出上限,直接导致程序崩溃、引用失效。解决方案:1、循环内每次使用完引用,立即调用DeleteLocalRef释放;2、大批量循环操作时,手动调用EnsureLocalCapacity扩容局部引用容量;3、将循环内的对象创建逻辑抽离,减少单次方法的引用创建数量。四、NDK多线程与并发1、JNI多线程开发有什么注意事项?原生线程如何回调Java层?参考答案:核心注意点:子线程不能直接使用主线程的JNIEnv指针。JNIEnv是线程私有变量,每个线程有独立的Env,跨线程使用会直接崩溃。原生子线程回调Java标准流程:1、在主线程中通过JavaVM获取虚拟机指针,全局保存;2、子线程执行回调前,调用AttachCurrentThread绑定线程,获取当前线程的JNIEnv;3、通过Env执行FindClass、调用Java回调方法;4、回调完成后,调用DetachCurrentThread解绑线程,释放资源。2、NDK多线程并发访问共享数据,如何保证线程安全?参考答案:1、C/C++层使用pthread互斥锁mutex,对共享变量、全局数据加锁,保证同一时间只有一个线程操作;2、避免多线程同时操作JNI对象引用,引用操作统一在单线程处理;3、对核心共享数据做原子操作,替代普通读写,避免简单并发冲突;4、禁止子线程直接更新UI,所有UI回调抛回Android主线程执行。五、JNI静态注册与动态注册1、JNI静态注册和动态注册的区别?各自优缺点?参考答案:静态注册:依靠方法名规则命名,Java_包名_类名_方法名,自动匹配Java原生方法。优点:简单、入门友好,无需手动写注册逻辑;缺点:方法名极长、可读性差、无法混淆、编译慢、不适合大批量方法。动态注册:通过JNI_OnLoad方法,手动建立Java方法和C函数的映射表。优点:方法名简洁、支持代码混淆、加载速度快、适合大量原生方法;缺点:需要手动维护映射表,新增方法需要手动添加注册逻辑。2、JNI_OnLoad作用是什么?执行时机?参考答案:JNI_OnLoad是so库加载时的入口函数。执行时机:System.loadLibrary加载so文件时,系统自动调用该方法,早于所有原生方法调用。核心作用:1、完成JNI方法动态注册;2、初始化全局变量、全局引用、线程、工具配置;3、校验JNI版本,返回当前支持的JNI版本。六、NDK性能优化与崩溃问题1、NDK开发中如何优化性能?参考答案:1、减少JNI跨层调用。Java和C++互调开销大,尽量批量处理数据,不要频繁单次调用;2、缓存JNI资源。全局缓存jclass、methodID、fieldID,不要每次方法调用都FindClass、GetMethodID;3、减少数据拷贝。尽量使用直接缓冲区DirectBuffer,避免数组、字符串频繁拷贝;4、线程优化。耗时运算放在原生子线程,避免阻塞主线程,控制线程数量,避免线程频繁创建销毁;5、编译优化。Release包开启O2编译优化,Debug包关闭优化,兼顾调试和线上性能;6、内存复用。预分配内存池,频繁读写的数据复用内存空间,减少malloc/free频繁调用。2、NDK常见崩溃原因有哪些?如何排查?参考答案:常见崩溃场景:1、空指针、野指针访问:原生层操作未判空、指针越界、内存释放后重复使用;2、跨线程使用JNIEnv、错误的线程绑定解绑;3、引用溢出、内存泄漏导致OOM;4、方法签名错误、找不到对应Java方法导致调用崩溃;5、so库架构不匹配、依赖库缺失、加载时机错误;6、数组越界、堆栈溢出、内存踩踏。排查方式:1、通过logcat查看tombstone崩溃日志,定位崩溃行数、内存地址;2、使用addr2line工具将崩溃地址映射为具体代码行;3、ASAN内存检测工具排查内存越界、重复释放、野指针问题;4、分步注释代码、日志打印,缩小崩溃范围。七、实操业务面试题1、DirectBuffer和普通数组区别?为什么大数据传输推荐DirectBuffer?参考答案:普通byte[]数组:Java堆内存,JNI调用时需要拷贝一份数据到原生内存,读写都有拷贝开销,大数据量效率极低。DirectBuffer:直接内存,不属于Java堆,是操作系统直接分配的内存,Java层和原生层共用同一块内存,无需数据拷贝。业务场景:视频帧数据、文件流、大数据加密、网络流传输,全部使用DirectBuffer,大幅减少IO拷贝开销,提升运行效率。2、如何实现Java层调用NDK异步耗时任务,完成后回调Java?参考答案:整体实现流程:1、Java层定义回调接口,传入原生层;2、原生层通过全局引用持有回调对象、方法ID;3、NDK开启子线程
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 商洽办公场所租赁合同细节商洽函8篇
- 建筑施工安全标准与风险防控指引
- 金融投资顾问服务稳定性绩效评定表
- 智能制造用户数据加密配置指南
- 验收测试报告的确认函(8篇范文)
- 零售业店长店铺运营与销售能力绩效评定表
- 2026年人力资源管理系统更新通知函(3篇)
- 建筑节能门窗安装与验收规范手册
- IT部门效能考核表
- 建筑行业绿色建筑节能方案
- 新疆维吾尔自治区初中级档案职称考试(档案基础)手机备考题库及答案(2026年)
- 肿瘤心理干预沟通护理课件
- 2026年校招:中国银行试题及答案
- 2026年物业管理条例考核试题及答案
- 公共娱乐场所电气消防安全培训
- 2026秋新版道德与法治五年级上册教学课件:第七课第1课时 社会主义好-自力更生结硕果 有多个微课视频
- 第5课 中国人民站起来了 第1课时 课件(内嵌视频)2026-2027学年道德与法治五年级上册统编版
- 制造业公司绩效考核含全套KPI指标库
- 2026年《资料员》考试题库带答案(考试直接用)
- 水利水电工程基坑临边防护专项方案
- 2026年浙江省绍兴市越城区网格员招录真题(含答案)
评论
0/150
提交评论