jvm学习总结

122 阅读7分钟

方法区 堆区 虚拟机栈 本地方法栈 程序计数器

类加载器:

1.虚拟器自带加载器

2.启动类(根)加载器

3.扩展类加载器 ExtClassLoader

4.应用程序(系统)加载器 AppClassLoader

native关键字:

①native修饰的方法,说明java的作用范围达不到,去调用底层c语言的库。

②会进入本地方栈,调用本地方法接口(JNI),作用扩展Java的使用,融合不同的编程语言为Java所用,最初想融合c和c++。

③它在内存区域中专门开辟了一块区域:本地方法栈,登记native方法。

虚拟机栈:存储一个方法的所有局部变量 (线程私有)

先进后出

栈帧:比如a = 1, 先是操作数栈1,局部变量a,再把1赋给a。

方法出口:用来存储方法的返回的位置,返回到哪个位置。

动态链接:指程序运行期间完成的符号引用替换为直接内存引用。找到方法在方法区的地址、指针等

如果是对象,存储对象在堆内存的引用

栈大小分为,所有线程和每个线程

-xss 设置虚拟机栈(每个线程) 默认1M

本地方法栈:存放native方法的局部变量 (线程私有的)

程序计数器:用来记录程序运行的行号,或者内存位置。(线程私有)

方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。这区域的内存回收目标主要是针对常量池的回收和对类型的卸载。(线程共享)

堆:主要分为三块,Eden(8/10),Survivor( from(1/10) , to(1/10) ) (2/10),老年代(2/3)

用于存储Java中的对象和数组,当我们new一个对象或者创建一个数组的时候,就会在堆内存中开辟一段空间给它,用于存放(线程共享)

①Eden区满了,会执行一次minorGC,清理Eden区和survivor区

②GC的时候Survivor放不下时,对象会直接进老年代

③一个对象每经过一次minorGC,+1,到15放到老年代。(在对象头)

④老年代满了,会触发一次Full GC,对整个堆区域、方法区进行垃圾回收,停止整个应用程序工作。

⑤Eden放不下的对象直接进老年代。

⑥大对象直接放在老年代,-XX:PretenureSize设置,只在Serial和ParNew收集器下有效

⑦对象动态年龄判断:minorGC时,判断一批对象的年龄总大小,当加到n时超过了to区或者from区的50%,把年龄为n只有的对象,直接挪到老年代区。

⑧老年代空间分配担保机制:

(1)年轻代每次mimor GC之前JVM会计算老年代剩余可用空间,如果可用空间小于年轻代里所有对象,查看一个参数-XX:-HandlePromotionFailur是否设置,如果设置了,就会查看老年代的可用空间是否大于之前每次minor gc后进入老年代对象的平均大小。

(2)如果是小于或者之前参数没有设置,触发一此Full GC,回收完还没有足够的空间存放新生代的新对象,发生OOM。

(3)每次minor gc之后存活的需要移动到老年代的对象,大于老年代可用空间,会full gc,还不够放,发生OOM。

判断对象是否可以回收:

引用计数法:给对象添加一个引用计数器,每当一个地方引用它,计数器+1;引用失效,计数器-1,

计数器为0的对象就不能再被使用(当引用构成环了,不能被回收,会造成内存泄漏)(早期虚拟机)

可达性分析算法:通过一系列GC Roots的对象作为起始点,从起始点开始向下搜索,找到的对象标记为非垃圾对象,其余的未被标记的对象都是垃圾对象,要被回收。

GC Roots根:栈内存的局部变量,常量,静态变量,本地方法栈的变量。

finalize()方法最终判定对象是否存活:

(1)第一次标记进行筛选,对象没有覆盖finalize()方法,对象直接被回收

(2)第二次标记,如果对象覆盖了finalize()方法,只要重新与引用链上的任何一个对象建立关系即可。

引用类型:

强引用:普通的变量引用,new出来的。

软引用:对象被软引用对象包裹,new SoftReference。正常不会被回收,GC做完后发现空间不够存新对象,就把软引用对象回收掉。

弱引用:对象用WeakReference弱引用类型对象包裹, new WeakReference。GC时直接回收掉。

虚引用:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

垃圾收集算法:

目前主流的JVM(Hotspot)采用的是分代收集算法

标记-清除算法:标记所有需要回收的对象,标记完成后回收所有被标记的对象。

缺点:效率问题;标记清楚后产生大量不连续的碎片。

复制算法:将内存分为大小相同的两块,每次只用一块,当一块用完了,就将存活的对象复制到另外一块上,将已经使用过的内存空间一次性清理掉。

标记-整理算法:将所有存活的对象都向一端移动,直接清理边界以外的内存。

分代收集算法:新生代,采用复制算法;老年代,采用标记-清除或者标记-整理算法。

垃圾收集器:

Serial收集器:单线程收集器,进行垃圾收集时暂停其他线程的所有工作(Stop The Work)。新生代采用复制算法,老年代采用标记-整理算法。(-XX:+UserSerialGc, -XX:+UserSerialOldGc)

ParNew收集器:serial收集器的多线程版本。和cpu核数相同,回收新生代(-XX:+UserParNewGc)。与Cms搭配使用,回收老年代。

Paraller Scavenge收集器:收集器类似于ParNew收集器,Server模式(内存大于2G,2个cpu)。吞吐量,是指运行用户代码时间/(运行用户代码时间+垃圾收集时间)(-XX:+UserParallelGc, -XX:+UserParallelOldGC),新生代采用复制算法,老年代采用标记-整理算法。

CMS收集器:只用于老年代

(1)并发收集器,初始标记,停止所有线程,把与GC Root根 直接关联的对象标记出来

(2)并发标记,标记其他所有的可达对象。不停用户线程。

(3)重新标记,记录发生变化的对象。停所有线程

(4)并发清理,不停用户线程。

(5)重启线程(-XX:+UserConcMarkSweepGc)

默认使用标记清除算法。

优点:并发收集,低停顿。

缺点:

(1)对CPU资源敏感。

(2)无法处理浮动垃圾(并发清理时新产生的垃圾)

(3)采用标记清除算法,导致空间碎片产生,可配置参数,清理完成后再整理。

G1收集器:针对配备多颗处理器及大容量内存的机器。堆内存划分为多个独立的空间,叫region,最多2048(Eden Survivor,Old ,Humongous)

(1)初始标记:暂停所有其他线程,记录下GC Roots直接引用的对象。

(2)并发标记:标记其他所有的可达对象。不停用户线程。

(3)最终标记:记录发生变化的对象。停所有线程

(4)筛选回收:筛选回收阶段首先对各个Region回收价值和成本进行排序。根据指定GC停顿时间,制定回收计划