方法区 堆区 虚拟机栈 本地方法栈 程序计数器
类加载器:
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停顿时间,制定回收计划