不知道为什么,就是想分享一些面试题!

2020-12-16 10:52:21 浏览数 (1)

今天是码妞给大家带来《每日一道面试题》的第十六期啦~

01

AOT和JIT以及混合编译的区别、优势

AOT和JIT是什么?AOT,即Ahead-of-time,指预先编译. JIT,即Just-In-Time,指即时编译.

区别: 主要区别在于是否在“运行时”进行编译.

优劣: AOT优点:1.在程序运行前编译,可以避免在运行时的编译性能消耗和内存消耗. 2.可以在程序运行初期就达到最高性能. 3.可以显著的加快程序的启动. AOT缺点:1.在程序运行前编译会使程序安装的时间增加. 2.牺牲Java的一致性. 3.将提前编译的内容保存会占用更多的外存.

JIT优点:1.可以根据当前硬件情况实时编译生成最优机器指令(ps:AOT也可以做到,在用户使用是使用字节码根据机器情况在做一次编译). 2.可以根据当前程序的运行情况生成最优的机器指令序列. 3.当程序需要支持动态链接时,只能使用JIT. 4.可以根据进程中内存的实际情况调整代码,使内存能够更充分的利用. JIT缺点:1.编译需要占用运行时资源,会导致进程卡顿. 2.由于编译时间需要占用运行时间,对于某些代码的编译优化不能完全支持,需要在程序流畅和编译时间之间做权衡. 3.在编译准备和识别频繁使用的方法需要占用时间,使得初始编译不能达到最高性能.

混合编译: Android N引入了使用编译 解释 JIT的混合运行时,以获得安装时间,内存占用,电池消耗和性能之间的最佳折衷. 优点: 即使是大型应用程序的安装时间也减少到几秒钟. 系统更新安装得更快,因为它们不需要优化步骤. 应用程序的RAM占用空间较小,在某些情况下降至50%. 改善了表现. 降低电池消耗.

参考:

https://source.android.com/devices/tech/dalvik https://www.infoq.com/news/2016/03/android-n-aot-jithttps://player.fm/series/android-developers-backstage-1245114/episode-45-state-of-the-art

02

Java对象的内存分配过程是如何保证线程安全的

在Java中,创建一个对象的方法有很多种,如使用new、使用反射、使用Clone方法等,但是无论如何,对象在创建过程中,都需要进行内存分配。拿最常见的new关键字举例,当我们使用new创建对象后代码开始运行后,虚拟机执行到这条new指令的时候,会先检查要new的对象对应的类是否已被加载,如果没有被加载则先进行类加载。在类加载检查通过之后,就需要给对象进行内存分配了,分配的内存主要用来存放对象的实例变量。在进行内存分配时,需要根据对象中的实例变量情况等信息确定需要分配的空间大小,然后从Java堆中划分出这样一块区域(假设没有JIT优化)。根据JVM使用的垃圾回收器的类型,因其回收算法不同,会导致堆中内存分配情况不同。如标记-清楚算法回收后的内存中会有大量不连续的内存碎片,在给新的对象分配的时候,就需要通过"空闲列表"来确定一块空闲区域。无论那种方式,最终都需要确定出一块内存区域,用于给新建对象分配内存。我们知道,对象的内存分配过程中,主要是对象的引用指向这个内存区域,然后进行初始化操作。

内存分配过程的线程安全性

  1. 对分配内存空间的动作做同步处理,采用CAS机制,配合失败重试的方式保证更新操作的线程安全性。 但是这种方案每次分配时都需要进行同步控制,这种是比较低效的。
  2. 每个线程在Java堆中预先分配一小块内存,然后再给对象分配内存的时候,直接在自己这块"私有"内存中分配,当这部分区域用完之后,再分配新的"私有"内存。 这种方案被称之为TLAB分配,即Thread Local Allocation Buffer。这部分Buffer是从堆中划分出来的,但是是本地线程独享的。这里值得注意的是,我们说TLAB时线程独享的,但是只是在“分配”这个动作上是线程独占的,至于在读取、垃圾回收等动作上都是线程共享的。而且在使用上也没有什么区别。 另外,TLAB仅作用于新生代的Eden Space,对象被创建的时候首先放到这个区域,但是新生代分配不了内存的大对象会直接进入老年代。因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。所以,虽然对象刚开始可能通过TLAB分配内存,存放在Eden区,但是还是会被垃圾回收或者被移到Survivor Space、Old Gen等。 我们使用了TLAB之后,在TLAB上给对象分配内存时线程独享的了,这就没有冲突了,但是,TLAB这块内存自身从堆中划分出来的过程也可能存在内存安全问题啊。所以,在对于TLAB的分配过程,还是需要进行同步控制的。但是这种开销相比于每次为单个对象划分内存时候对进行同步控制的要低的多。虚拟机是否使用TLAB是可以选择的,可以通过设置-XX: /-UseTLAB参数来指定。

总结

为了保证Java对象的内存分配的安全性,同时提升效率,每个线程在Java堆中可以预先分配一小块内存,这部分内存称之为TLAB(Thread Local Allocation Buffer),这块内存的分配时线程独占的,读取、使用、回收是线程共享的。

可以通过设置-XX: /-UseTLAB参数来指定是否开启TLAB分配。

参考资料:

《深入理解Java虚拟机》

https://www.cnblogs.com/straybirds/p/8529924.html

https://www.zhihu.com/question/56538259

03

WebView的漏洞有哪几种

主要三类漏洞:

  1. WebView 中 addJavascriptInterface() 接口
  2. WebView 内置导出的 searchBoxJavaBridge_对象
  3. WebView 内置导出的 accessibility 和 accessibilityTraversalObject 对象
  4. 任意代码执行漏洞

WebView 中 addJavascriptInterface()接口

原因 JS调用Android的其中一个方式是通过addJavascriptInterface接口进行对象映射,当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。 解决 Android 4.2以前,需要采用**拦截prompt()**的方式进行漏洞修复 Android 4.2以后,则只需要对被调用的函数以 @JavascriptInterface进行注解

WebView 内置导出的 searchBoxJavaBridge_对象

原因 在Android 3.0以下,Android系统会默认通过searchBoxJavaBridge_的Js接口给 WebView 添加一个JS映射对象:searchBoxJavaBridge_对象 该接口可能被利用,实现远程任意代码。

解决 删除searchBoxJavaBridge_接口

WebView 内置导出的 accessibility 和 accessibilityTraversalObject 对象 原因和解决方法同上

密码明文存储漏洞

原因 WebView默认开启密码保存功能:mWebView.setSavePassword(true) 开启后,在用户输入密码时,会弹出提示框:询问用户是否保存密码; 如果选择”是”,密码会被明文保到 /data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险 解决 关闭密码保存提醒:WebSettings.setSavePassword(false)

域控制不严格漏洞

getSettings类的方法对 WebView 安全性的影响

setAllowFileAccess // 设置是否允许 WebView 使用 File 协议

webView.getSettings().setAllowFileAccess(true); 如果不允许使用 file 协议,则不会存在上述的威胁;但同时也限制了 WebView 的功能,使其不能加载本地的 html 文件

解决 对于不需要使用 file 协议的应用,禁用 file 协议; 对于需要使用 file 协议的应用,禁止 file 协议加载 JavaScript。

3.2 setAllowFileAccessFromFileURLs // 设置是否允许通过 file url 加载的 Js代码读取其他的本地文件 webView.getSettings().setAllowFileAccessFromFileURLs(true); // 在Android 4.1前默认允许 // 在Android 4.1后默认禁止

解决方案 设置setAllowFileAccessFromFileURLs(false);

setAllowUniversalAccessFromFileURLs // 设置是否允许通过 file url 加载的 Javascript 可以访问其他的源(包括http、https等源)

webView.getSettings().setAllowUniversalAccessFromFileURLs(true); // 在Android 4.1前默认允许(setAllowFileAccessFromFileURLs()不起作用) // 在Android 4.1后默认禁止

解决方案 设置setAllowUniversalAccessFromFileURLs(false);

参考: https://blog.csdn.net/carson_ho/article/details/64904635

04

说说你对线程池的理解

使用线程池的原因:

  1. 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  2. 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大)。

线程池的分类:

  1. 线程池都是通过Executors来创建的。
  2. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  3. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  4. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  5. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。

线程数解析:

  1. corePoolSize: 线程池维护线程的最少数量。
  2. maximumPoolSize:线程池维护线程的最大数量。
  3. keepAliveTime: 线程池维护线程所允许的空闲时间。
  4. workQueue: 线程池所使用的缓冲队列。
  5. handler: 线程池对拒绝任务的处理策略。

创建规则: 一个任务通过execute(Runnable)方法欲添加到线程池时:

  1. 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
  2. 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
  3. 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
  4. 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
  5. 当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

终止和关闭线程池:

hreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:

  1. Shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务。
  2. ShutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务。

05

简单描述一下Intent和IntentFilter

Intent 是 Android 程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组 件想要执行的动作,还可以在不同组件之间传递数据。Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。通过Intent 可以实现各种系统组件的调用与激活。Intent是我们经常用的,想必都不陌生。 而IntentFilter是用于描述intent的各种属性。可以理解为邮局或者是一个信笺的分拣系统: 这个分拣系统通过3个参数来识别,匹配优先级:action>data>category Action: 动作 view Data: 数据uri uri Category : 另外的附加信息

Action 匹配: Action 是一个用户定义的字符串,用于描述一个 Android 应用程序组件,一个 IntentFilter 可以包含多个Action。在 AndroidManifest.xml 的 Activity 定义时可以在其 节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,例如: …… 如果我们在启动一个 Activity 时使用这样的 Intent 对象: Intent intent =new Intent(); intent.setAction("com.myself.action"); 那么所有的 Action 列表中包含了“com.myself”的 Activity 都将会匹配成功。 Android 预定义了一系列的 Action 分别表示特定的系统动作。这些 Action 通过常量的方式定义在 android.content. Intent中,以“ACTION_”开头。我们可以在 Android 提供的文档中找到它们的详细说明。 URI 数据匹配: 一个 Intent 可以通过 URI 携带外部数据给目标组件。在 节点中,通过 节点匹配外部数据。mimeType 属性指定携带外部数据的数据类型,scheme 指定协议,host、port、path 指定数据的位置、端口、和路径。如下:

电话的uri: tel: 12345 网址的uri:http://www.baidu.com 自己定义的uri:content://com.myself.app/self 如果在 Intent Filter 中指定了这些属性,那么只有所有的属性都匹配成功时 URI 数据匹配才会成功。 Category 类别匹配: 节点中可以为组件定义一个 Category 类别列表,当 Intent 中包含这个列表的所有项目时Category 类别匹配才会成功。

06

结束语

如果你有好的答案可以提交至:

https://github.com/codeegginterviewgroup/CodeEggDailyInterview

0 人点赞