目录
1.内存区域划分【物理】
2.垃圾回收
3.Java中volatile的作用
线程私有区:
1)程序计数器:可看作是当前线程所执行字节码的行号指示器
2)虚拟机栈【-Xss:设置栈的深度】
----虚拟机栈描述的是Java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈的过程。声明周期与线程相同。
局部变量表:存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间完全确定的,在执行期间不会改变局部变量表大小。
虚拟机栈会产生两种异常:
a.如果线程请求的栈深度大于虚拟机所允许的深度,会抛出StackOverFlowError异常
b.虚拟机在动态扩展时无法申请到足够的内存,会抛出OOM
3)本地方法栈
与虚拟机栈不同的是虚拟机栈为JVM执行的Java方法服务,而本地方法栈为虚拟机使用的Native方法使用
线程共享区:
如何判断对象是否存活?à唤醒阶段(Object类的finalize())à如何进行垃圾回收(GC算法)
2.1判断对象是否存活:
(1)引用计数【无法解决对象循环引用问题】
----给对象增加一个计数器,每当有一个地方引用它时,计数器就加1;当引用失效时,计数器减1;任何时刻计数器为0的对象就是不能再被使用的,即对象已“死”。
(2)可达性分析:
哪些对象可以作为GC Roots
(1)本地方法栈、虚拟机栈中中引用的对象;
(2)类中的静态变量与常量
**JDK1.2关于引用的扩充**[如下表所示]
强引用 |
程序中普遍存在的例,只要对象被任意一个强引用指向,无论是否发生内存溢出,都不能回收被强引用指向的对象
|
软引用 |
SoftReference描述软引用,若对象只被软引用指向,当内存够用时不回收此对象,当内存不够用时,会回收掉所有被软引用指向的对象,软引用对象为有用但非必需对象,(如缓存对象)
|
弱引用 |
弱引用也是用来描述非必需对象的。但是它的强度要弱于软引用,被弱引用关联的对象只能生存到下一次垃圾回收发生之前,当垃圾回收器开始进行工作时,无论当前内容是否够用,都会回收掉只被弱引用关联的对象。使用WeakeReference类来实现弱引用。
|
虚引用 |
虚引用也被称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。
|
注:即使在可达性分析算法中不可达的对象,也并非“非死不可”的,这时候它们暂时处在“缓刑阶段”。要宣告一个对象的真正死亡,至少要经历两次标记过程:如果对象在进行可达性分析之后发现没有与GCRoots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者是已经被JVM调用过,虚拟机会将这两种情况都视为“没有必要执行”,此时的对象才是真正“死对象”
如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个叫做F-Queue的队列之中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它(这里所说的执行指的是虚拟机会触发finalize()方法)fianalize()方法是对象逃脱死亡的最后一次次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象在finalize()中成功拯救自己(只需要重新与引用链上的任何一个对象建立起关联关系即可),那在第二次标记时它将会被移出“即将回收”的集合;如果对象这时候还是没有逃脱,基本上它就是真的被回收了。
2.2垃圾回收算法
(1)标记-清除算法【最基础的收集算法】
a.标记:标记处所有需要回收的对象
b.清除:在标记完成之后统一回收所有被被标记的对象
不足:
a.效率问题:标记和清除这两个过程的效率都不高
b.空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致程序运行中需要大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。
(2)复制算法:
将可用内存划分为大小相等的两块,每次只使用其中的一块,当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。这样做的好处是每次都是对整个半区进行内存回收,内存分配时也就不需要考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配即可。
新生代中98%的对象都是“朝生夕死的”,所以并不需要按照1:1的比例来划分内存空间,而是将内存(新生代内存)分为一块较大的Eden(伊甸园)空间和两块较小的Survivor(幸存者空间),每次使用Eden和其中一块Survivor(两个survivor区域一个称为From区,一个称为To区域)。当回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间
HotSpot实现的复制算法流程:
(3)标记整理算法(老年代回收算法)
与“标记-清除”过程一致,但后续步骤不回收直接对可回收对象进行清理,而是让所有存活对象都想一端移动,然后直接清理掉。
当前JVM垃圾收集都采用的是“分代收集”算法,这个算法并没有新思想,只是根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代。在新生代中,每次回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而在老年代中独享存活率较高。没有额外空间对它进行分配担保,就必须采用“标记-清除”或者“标记整理算法”
**了解Minor GC和Full GC么,这两种GC有什么不一样吗?
Minnor GC又称为新生代GC:指的是发生在新生代的垃圾收集。因为Java对象大多都具备招生夕灭的特性,因此Minor GC(复制算法)非常频繁,一般回收速度也比较快
Full GC又成为老年代GC或者Major GC:只发生在老年代的垃圾收集。出现了Major GC,经常会伴随至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器中就有直接进行Full GC 的策略选择过程)Major GC的速度一般会比Minor GC慢10倍以上