分类: Android

  • JAVA知识总结

    1、jdk自带线程池为什么先入队列,后创建非核心线程?
    因为队列增加一个元素的成本更低。

    2、内部类引用外部类方法的局部变量,为什么必须使用final修饰?
    因为外部类方法的变量运行完毕就会回收,但加载的内部类可能仍然存在。

    3、方法的签名包括方法名和参数列表,为什么不包括返回值?
    因为调用端可以不接收返回值,此种情况就无法判断具体是哪个方法。

    4、Spring的线程池工具ThreadPoolTaskExecutor,也是基于JDK的ThreadPoolExecutor实现,它有什么好处、陷阱?
    好处:参数、单例可配置,队列、拒绝策略有默认。缺点:错过了解底层的机会,直接使用ThreadPoolExecutor也不难。

    5、有哪些令人眼花缭乱的锁?
    自旋、阻塞、重入、读写、乐观、悲观、偏向、轻量级、重量级,共享锁、排他锁、行锁、表锁、间隙锁、意向锁。

    6、状态模式与策略模式有什么区别?
    结构上看,没有区别。
    目的上看,
    状态模式由一组状态驱动,用于处理状态的变化;
    策略模式由一组算法驱动,用于处理算法的变化。
    具体来说,
    策略模式中,算法是否变化完全由客户端决定,而且一般一次只能选择一种算法,不存在中途变化的情况;
    状态模式中,状态本身存在线性的生命周期,是否变化由具体状态内部决定,这种变化对客户端是透明的。

    7、HashMap.put(key, value)的执行过程。
    计算key的哈希值。
    计算哈希值在数组中的位置。
    若该key已存在,则替换掉旧值。
    否则,在该位置添加新的节点。
    最后检查是否需要扩容。

    8、HashMap何时扩容?怎么扩容?数据迁移?
    何时扩容?
    put的最有一步,若size>=threshold(capcity*loadFactor),则进行扩容。
    怎么扩容?
    创建一个新数组,容量=旧数组容量*2。
    将旧数组中的数据,迁移到新数组。
    将HashMap的底层数组指向新数组。
    重新计算threshold。
    数据迁移?
    遍历旧数组。
    针对每个数组成员,从头开始遍历链表。
    针对每个链表节点,重新计算哈希值,以及该哈希值在新数组中的位置。
    将当前节点的next,指向新数组中该位置的节点。
    将新数组中该位置,指向当前节点。
    以上过程造成了两种后果:
    若重新哈希后没有冲突,直接存放为数组元素;
    若重新哈希后仍有冲突,新链表的顺序与原来相反。

    9、HashMap.get(key)多线程环境下,CPU飙到100%。
    根本原因,在HashMap扩容,数据迁移的时候,出现了环状链表结构。
    相关代码:
           void transfer(Entry[] newTable)
           {
                  Entry[] src = table;
                  int newCapacity = newTable.length;
                  // 下面这段代码的意思是:
                  // 从OldTable里摘一个元素出来,然后放到NewTable中
                  for (int j = 0; j < src.length; j++) {
                         Entry<K,V> e = src[j];
                         if (e != null) {
                                src[j] = null;
                                do {
                                       Entry<K,V> next = e.next; // 线程一在这里挂起
                                       int i = indexFor(e.hash, newCapacity);
                                       e.next = newTable[i];
                                       newTable[i] = e;
                                       e = next;
                                } while (e != null);
                         }
                  }
           }
    形成过程:
    为了便于分析问题,假定链表长度为2,头结点为node1,尾节点为node2。
    第一阶段->线程1>第1次循环>上半场
    创建数组a,遍历旧链表,第1个语句,之后当前线程挂起;
    此时情况,持有两个引用,e指向头结点(node1),next指向尾节点(node2),即e.next。
    第二阶段->线程2。
    创建数组b,遍历旧链表,完毕之后,新链表的顺序与原来相反。
    此时情况,node1变成了尾节点,node2变成了头结点。
    b[i]=node2,node2.next=node1,node1.next=null。
    第三阶段>线程1>第1次循环>下半场
    初始情况,e指向尾节点(node1),next指向头结点(node2)。
    第2个语句,计算尾节点e(node1)的数组下标i。
    第3个语句,尾节点e(node1)的next(e.next),指向a[i](此时为null)。
    第4个语句,a[i]指向尾节点e(node1)。
    第5个语句,e指向头结点next(node2)。
    此时情况,a[i]指向尾节点(node1),e指向头结点(node2),next也指向头结点(node2)。
    a[i]=node1,node1.next=null,b[i]=node2,node2.next=node1。
    第四阶段>线程1>第2次循环
    第1个语句,next指向尾节点(node1)。
    第2个语句,计算头结点e(node2)的数组下标i。
    第3个语句,头结点e(node2)的next(e.next),指向a[i](此时为node1),相当于node2.next=node1。(没有任何效果)
    第4个语句,a[i]指向头结点e(node2)。
    第5个语句,e指向尾节点next(node1)。
    此时情况,a[i]指向头节点(node2),e指向尾结点(node1)。
    a[i]=node2,node2.next=node1,node1.next=null,b[i]=node2。
    第五阶段>线程1>第3次循环
    第1个语句,next指向null。
    第2个语句,计算尾结点e(node1)的数组下标i。
    第3个语句,尾结点e(node1)的next(e.next),指向a[i](此时为node2),即node1.next=node2。
    总结。
    第四阶段,node2.next=node1。
    第五阶段,node1.next=node2。
    由此环路形成。

    10、HashSet.toString()多线程环境下,出现内存溢出。
    两个原因,
    HashSet基于HashMap实现,多线程环境下,出现了环状链表结构。
    HashSet.toString拼装StringBuilder时,遍历上述结构,陷入死循环。

    11、两阶段提交和三阶段提交。
    两阶段提交:
    第一阶段,投票+预提交(各就各位+预备);
    第二阶段,提交(走你)。
    三阶段提交:
    第一阶段,投票(各就各位);
    第二阶段,预提交(预备);
    第三阶段,提交(走你)。

    12、JDK6、JDK7、JDK8,常量池、方法区(永久代)、元空间。
    JDK6,常量池位于方法区,又叫永久代,配置参数-XX:PermSize、-XX:MaxPermSize
    JDK7,常量池位于堆内存。
    JDK8,彻底去掉了方法区,取而代之的是元空间,配置参数-XX:MetaspaceSize、-XX:MaxMetaspaceSize

    13、TLAB是什么?它位于堆内存,还是栈内存?

    14、对象可以直接分配在栈内存吗?

    15、JVM线上问题分类排查。
    CPU问题。
    死循环:查看系统负载,排查方法:top/top H/top -Hp pid。
    线程阻塞:查看线程栈,排查方法:jstack pid。
    频繁GC:查看GC情况,排查方法:jstat -gcutil pid。
    内存类问题。
    堆内存:OutOfMemoryError:java heap space,排查方法:集合、缓存、多线程、大对象、jmap –heap、jmap –histo、jmap -dump:format=b,file=xxx.hprof。
    栈内存:
    StackOverflowError,排查方法:栈深度过大、递归死循环等;
    OutOfMemoryError:unable to create new native thread,排查方法:线程数量过多、物理内存不足、超过系统限制
    方法区:OutOfMemoryError:PermGen space,排查方法:XX:MaxPermSize、class/jar过多、重复加载、动态代理。
    直接内存:OutOfMemoryError,排查方法:Java Native Interface、java.nio.DirectByteBuffer等
    IO类问题。
    磁盘IO。
    网络IO。

    16、栈内存什么情况下StackOverflowError,什么情况下OutOfMemoryError?
    单个线程的栈帧太大,抛出StackOverflowError。
    创建的线程数量过多,抛出OutOfMemoryError。

    17、强引用、软应用、弱引用、虚引用。
    强引用,诸如Object obj = new Object(),永远不会垃圾回收。
    软引用,诸如SoftReference reference = new SoftReference(obj),在内存溢出之前,进行二次回收。
    弱引用,诸如WeakReference reference = new WeakReference(obj),下一次垃圾回收时进行回收。
    虚引用,诸如PhantomReference reference = new PhantomReference(obj),对垃圾回收无任何影响,也无法通过虚引用取得对象,它存在的唯一目的,就是对象被回收时,收到一个系统通知。

    18、判定对象是否应该被回收,引用计数器 OR 可达性分析?
    答案是可达性分析,因为引用计数器无法解决循环引用的问题。
    可达性分析是指,从对象到GC Roots没有任何引用链相连接。
    GC Roots包含,虚拟机栈和本地方法栈中引用的对象,方法区中静态成员变量和常量引用的对象。

    19、对象被判定为不可达后,是否非死不可?
    答案是NO。
    标记对象是否有必要执行finalize方法(对象覆盖了finalize方法,且未执行过,表示有必要执行)
    若无必要执行,则进行回收。
    创建的线程数量过多,抛出OutOfMemoryError。
    若有必要执行,则登记F-Queue队列,启动Finalizer线程,执行finalize方法。
    若finalize方法中把对象复活,则对象不进行回收,否则进行回收。
    以上复活的机会只有一次,下一次finalize方法不再执行

    20、CPU负载飙高甚至达到100%,如何排查?
           第一步,找到CPU负载最高的进程pid:top/top -c
    第二步,找到CPU负载最高的线程pid:top -Hp pid。
    第三步,线程pid转换为十六进制:printf ‘%x\n’ pid。
    第四步,找到Java堆栈信息:jstack 进程pid | grep 线程pid十六进制 -C10 –color。
    第五步,定位到线程信息和问题代码。

    21、JVM参数-XX:+DisableExplicitGC、-XX:+ExplicitGCInvokesConcurrent的含义。
    -XX:+DisableExplicitGC,禁用System.gc()显式调用GC。
    -XX:+ExplicitGCInvokesConcurrent,启用并行的FullGC。
    常与堆外直接内存配合使用。(?)

    22、什么是堆外内存?
    狭义的堆外内存,通过java.nio.DirectByteBuffer分配的内存,通过JVM参数-XX:MaxDirectMemorySize指定大小
    若未指定,则默认=新生代+老生代-survivor=-Xmx-survivor
    广义的堆外内存,堆之外的所有内存,包含程序计数器、虚拟机栈、本地方法栈、直接内存。
    注意:对于HotSpot,Java6/Java7的方法区又叫永久代,与堆内存一起分配和管理,因此属于堆内存的一部分。
    对于频繁操作内存,只需临时存储的场景,建议使用堆外内存,并且做成缓冲池,便于重复利用。

    23、使用堆外内存,为什么显式调用GC?
    DirectByteBuffer对象创建的时候,关联PhantomReference用于对象跟踪,创建sun.misc.Cleaner用于对象回收。(Unsafe的free接口。)
    GC过程中,若发现对象只被PhantomReference引用,则该引用登记到java.lang.ref.Reference.pending队列
    GC完毕后,通知ReferenceHandler守护线程进行后置处理,若pending队列为空,则线程阻塞,否则进行遍历
    若Reference类型为Cleaner,则调用Cleaner.clean(),否则登记ReferenceQueue队列,可以用于对象的复活。(类似于finalizer)

    24、JVM监控小工具jstat。
          
     jstat -gc pid——S0C、S1C、S0U、S1U、EC、EU、OC、OU、PC、PU、YGC、YGCT、FGC、FGCT、GCT
           jstat -gcutil pid——S0、S1、E、O、P、YGC、YGCT、FGC、FGCT、GCT。
           jstat -gccapacity pid。
    jstat -gccause pid。

    25、-XX:+DisableExplicitGC,关闭System.gc(),亦即禁止手动触发STW的FGC。

    26、-XX:+ExplicitGCInvokesConcurrent,YGC+部分OGC,性能比Full GC要好,STW时间变短,后台回收。

    27、

  • JVM性能调优-收集

    1、JVM源码分析之SystemGC完全解读
    http://mp.weixin.qq.com/s/V1Y6DIoscTuv7RVlIZgVpw

    2、JVM源码分析之堆外内存完全解读
    http://mp.weixin.qq.com/s/WgQkXxBJDF7QdTHFFGVypg

    3、JVM源码分析之Object.wait/notify(All)完全解读
    http://mp.weixin.qq.com/s/4oCEWVrs67aONxEgMaOVFg

    4、JDK的sql设计不合理导致的驱动类初始化死锁问题
    http://mp.weixin.qq.com/s/XVXEZK71ZKGbIgvCGl7tIg

    5、JVM源码分析之FinalReference完全解读
    http://mp.weixin.qq.com/s/-ER8S28tb17-f51S_NgADQ

    6、如何定位消耗CPU最多的线程
    http://mp.weixin.qq.com/s/c-KuGjI_VH1dTxIWtxZJEg

    7、不可逆的类初始化过程
    http://mp.weixin.qq.com/s/HK5JsmGjvOe_93TwlmZNdg

    8、JVM源码分析之javaagent原理完全解读
    http://mp.weixin.qq.com/s/OLeWL70E0qFACzw5Ri8GTw

    9、JDK8在泛型类型推导上的变化
    http://mp.weixin.qq.com/s/lz5RyWUmneCDpGSqyVLy9Q

    10、JVM源码分析之自定义类加载器如何拉长YGC
    http://mp.weixin.qq.com/s/fiuB2f3Gv5XDka0rrP2eAw

    11、进程物理内存远大于Xmx的问题分析
    http://mp.weixin.qq.com/s/XJ1xXz8dtMv1DVcZVf73GA

    12、JVM源码分析之Attach机制实现完全解读
    http://mp.weixin.qq.com/s/-ER8S28tb17-f51S_NgADQ

    13、JVM源码分析之栈溢出完全解读
    http://mp.weixin.qq.com/s/1d8W-eyzsnGDr9-uSfag6Q

    14、JVM源码分析之JDK8下的僵尸(无法回收)类加载器
    http://mp.weixin.qq.com/s/mbLuRjfw56wglBmOdtVskQ

    15、消失的死锁
    http://mp.weixin.qq.com/s/KOzt6kOXH3MapR3Ug43gvw

    16、YGC前后新生代变大
    http://mp.weixin.qq.com/s/YigddMVvRj7nO1xAZOXa1Q

    17、诡异GC问题收集
    http://mp.weixin.qq.com/s/rX6mDmZDQ9SWtze4F0hvvQ

    18、JVM源码分析之jstat工具原理完全解读
    http://mp.weixin.qq.com/s/gCE9eXbtMuze3jhuRm1YXA

    19、JVM源码分析之不可控的堆外内存
    http://mp.weixin.qq.com/s/MgMYy-K0G753-_qCsqFyVA

    20、JVM源码分析之临门一脚的OutOfMemoryError完全解读
    http://mp.weixin.qq.com/s/M8TFyVzS5MvwL2M639m3Bg

    21、JVM源码分析之Metaspace解密
    http://mp.weixin.qq.com/s/SsXbRvtvawKDHstFpU4uog

    22、JVM源码分析之不保证顺序的Class.getMethods
    http://mp.weixin.qq.com/s/XrAD1Q09mJ-95OXI2KaS9Q

    23、JVM源码分析之String.intern()导致的YGC不断变长
    http://mp.weixin.qq.com/s/RtIZd4zaa-UkxoxtUsXd8Q

    24、JVM源码分析之自定义类加载器如何拉长YGC
    http://mp.weixin.qq.com/s/rsYm1WTMKv5V2SRHmwSdlw

    25、Java的时间为何从1970年1月1日开始
    http://mp.weixin.qq.com/s/mUTOMe4rXhKWp5sOHZK9Xw

    26、JVM源码分析之System.currentTimeMillis及nanoTime原理详解
    http://mp.weixin.qq.com/s/w37FXrVjQL36i8m_WLpf_w

    27、JVM源码分析之一个Java进程究竟能创建多少线程
    http://mp.weixin.qq.com/s/K8Y1wOloEwj1yQGEf7TnZQ

    28、JVM源码分析之警惕存在内存泄漏风险的FinalReference(增强版)
    https://mp.weixin.qq.com/s/igboi4xvjT4hTEFqZjLxEA

    29、假笨说-从X86指令深扒JVM的位移操作
    http://mp.weixin.qq.com/s/Mbg4y8fZdE4Mi37uz8-czA

    30、假笨说-我是如何走上JVM这条贼船的
    http://mp.weixin.qq.com/s/u7AWMDORvYa1TV4La18ObQ

    31、假笨说-从一起GC血案谈到反射原理
    http://mp.weixin.qq.com/s/5H6UHcP6kvR2X5hTj_SBjA

    32、来云栖社区聊聊Java开发者规范吧
    https://mp.weixin.qq.com/s/9kFI8WDxreHszt0Xa7fl4g

    33、假笨说-谨防JDK8重复类定义造成的内存泄漏
    https://mp.weixin.qq.com/s/3sb_ovHhhTXTid3G5iZUew

    34、假笨说-类初始化死锁导致线程被打爆!打爆!爆!
    http://mp.weixin.qq.com/s/UwEO8hFq-EL3a_VjMRydkA

    35、假笨说-又抓了一个导致频繁GC的鬼–数组动态扩容
    http://mp.weixin.qq.com/s/HKdpmmvJKq45QZdV4Q2cYQ

    36、假笨说-关于数组动态扩容导致频繁GC的问题,我还有话说
    http://mp.weixin.qq.com/s/GuPpF5LWydwZVnEiz6KoHw

    37、假笨说-查JVM参数就找JVMPocket(JVM口袋)小程序吧
    http://mp.weixin.qq.com/s/XJrH8lN6N0i7juf2AKZmmA

    38、假笨说-给JVMPocket提建议,赠您JVM的好书,可好?
    http://mp.weixin.qq.com/s/sNB42zc60oRAZL9Y54-e6g

    39、假笨说-警惕大量类加载器的创建导致诡异的Full GC
    http://mp.weixin.qq.com/s/qgpMMR8-493-Y9uwWiMdRg

    40、揪出一个导致GC慢慢变长的JVM设计缺陷
    http://mp.weixin.qq.com/s/m0YpJuHB3pkrvUylYbe5eg

    41、假笨说-关于内存溢出,咱再聊点有意思的
    http://mp.weixin.qq.com/s/ET8C8VrbcCLFSipCLKgvYA

    42、假笨说-JVM参数,我准备做些分享,你想听吗
    http://mp.weixin.qq.com/s/OhalT8Y4MgOWCiNA3y9iQg

    43、假笨说参数-对象晋升相关的MaxTenuringThreshold
    http://mp.weixin.qq.com/s/9NULcNlV7G4Ssgn5FSFzbg

    44、假笨说参数-GC日志其实也支持滚动输出的
    http://mp.weixin.qq.com/s/aGT31AQyH7NRqnRGArE2eg

     

  • Android SDK在线更新镜像服务器及使用方法

    中国科学院开源协会镜像站地址:

    IPV4/IPV6: http://mirrors.opencas.cn 端口:80

    IPV4/IPV6: http://mirrors.opencas.org 端口:80

    IPV4/IPV6: http://mirrors.opencas.ac.cn 端口:80

    上海GDG镜像服务器地址:

    http://sdk.gdgshanghai.com 端口:8000

    北京化工大学镜像服务器地址:

    IPv4: http://ubuntu.buct.edu.cn/ 端口:80

    IPv4: http://ubuntu.buct.cn/ 端口:80

    IPv6: http://ubuntu.buct6.edu.cn/ 端口:80

    大连东软信息学院镜像服务器地址:

    http://mirrors.neusoft.edu.cn 端口:80

    腾讯Bugly 镜像:

    http://android-mirror.bugly.qq.com 端口:8080

    腾讯镜像使用方法:http://android-mirror.bugly.qq.com:8080/include/usage.html

    使用方法:

    1.启动 Android SDK Manager
    2.打开主界面,依次选择『Tools』、『Options…』
    3.弹出『Android SDK Manager – Settings』窗口;
    4.在『Android SDK Manager – Settings』窗口中,在『HTTP Proxy Server』和『HTTP Proxy Port』输入框内填入上面镜像服务器地址(不包含http://)和端口,
    5.选中『Force https://… sources to be fetched using http://…』复选框
    6.设置完成后单击『Close』按钮关闭『Android SDK Manager – Settings』窗口返回到主界面;
    7.依次选择『Packages』、『Reload』
    OK!

Copyright © 2014-2025 奋奋的愤愤 | 京ICP备14029030号-1