内存模型以及分区,需要详细到每个区放什么。
JVM 分为堆区和栈区,还有方法区,初始化的对象放在堆里面,引用放在栈里面,class类信息常量池(static常量和static变量)等放在方法区
- 方法区:主要是存储类信息,常量池(static常量和static变量),编译后的代码(字节码)等数据
- 堆:初始化的对象,成员变量 (那种非static的变量),所有的对象实例和数组都要在堆上分配
- 栈:栈的结构是栈帧组成的,调用一个方法就压入一帧,帧上面存储局部变量表,操作数栈,方法出口等信息,局部变量表存放的是8大基础类型加上一个应用类型,所以还是一个指向地址的指针
- 本地方法栈:主要为Native方法服务
- 程序计数器:记录当前线程执行的行号
堆里面的分区:Eden,survival (from+ to),老年代,各自的特点。
堆里面分为新生代和老生代(java8取消了永久代,采用了Metaspace),新生代包含Eden+Survivor区,survivor区里面分为from和to区,内存回收时,如果用的是复制算法,从from复制到to,当经过一次或者多次GC之后,存活下来的对象会被移动到老年区,当JVM内存不够用的时候,会触发Full GC,清理JVM老年区
当新生区满了之后会触发YGC,先把存活的对象放到其中一个Survice区,然后进行垃圾清理。因为如果仅仅清理需要删除的对象,这样会导致内存碎片,因此一般会把Eden 进行完全的清理,然后整理内存。那么下次GC 的时候,就会使用下一个Survive,这样循环使用。如果有特别大的对象,新生代放不下,就会使用老年代的担保,直接放到老年代里面。因为JVM 认为,一般大对象的存活时间一般比较久远。
对象存活判断
引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。
可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。不可达对象。
在Java语言中,GC Roots包括:
虚拟机栈中引用的对象。
方法区中类静态属性实体引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI引用的对象。
SafePoint是什么
比如GC的时候必须要等到Java线程都进入到safepoint的时候VMThread才能开始执行GC,
- 循环的末尾 (防止大循环的时候一直不进入safepoint,而其他线程在等待它进入safepoint)
- 方法返回前
- 调用方法的call之后
- 抛出异常的位置
GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?
标记:标记完毕之后再清除,效率不高,会产生碎片
复制算法:分为8:1的Eden区和survivor区,就是上面谈到的YGC
标记整理:标记完毕之后,让所有存活的对象向一端移动
GC收集器有哪些?CMS收集器与G1收集器的特点。
串行收集器:串行收集器使用一个单独的线程进行收集,GC时服务有停顿时间
并行收集器:次要回收中使用多线程来执行
CMS:基于“标记—清除”算法实现的,经过多次标记才会被清除
G1:从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的
Minor GC与Full GC分别在什么时候发生?
新生代内存不够用时候发生MGC也叫YGC,JVM内存不够的时候发生FGC
几种常用的内存调试工具:jmap、jstack、jconsole、jhat
stack可以看当前栈的情况,jmap查看内存,jhat 进行dump堆的信息
mat(eclipse的也要了解一下)
g1 和 cms 区别,吞吐量优先和响应优先的垃圾收集器选择
CMS是一种以最短停顿时间为目标的收集器,响应优先选择CMS,吞吐量高选择G1
类加载的几个过程
加载、验证、准备、解析、初始化。然后是使用和卸载了
通过全限定名来加载生成class对象到内存中,然后进行验证这个class文件,包括文件格式校验、元数据验证,字节码校验等。准备是对这个对象分配内存。解析是将符号引用转化为直接引用(指针引用),初始化就是开始执行构造器的代码
双亲委派模型
Bootstrap ClassLoader:启动类加载器,负责将 Java_Home/lib下面的类库加载到内存中。(比如rt.jar)
Extension ClassLoader:标准扩展(Extension)类加载器,它负责将$Java_Home /lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。
ApplicationClassLoader:它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器
双亲委派模型是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。-----例如类java.lang.Object,它存在在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
少喝酒,少抽烟,少熬夜。多跑步,多喝茶,多看书。健康是最大的本钱,平安是福,对人对己,都是。学着感恩,学着理解,学着友善。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++