虚拟机启动时 创建,用于存放对象实例,几乎所有的对象(包括常量池)都在堆上分配内存,当 对象无法再该空间申请到内部时将抛出 OutOfMemoryError 异常。同时也是垃圾收集器管理的主要区域。可通过 -Xmx _xms参数来分别指定最大堆和最小堆。
新生区:
类诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集。
伊甸区(Eden space):所有的类都在该区域new 出来的,当伊甸区的空间用完时,程序又需要创建对象,JVM垃圾回收器将对伊甸区进行垃圾回收(Minor GC),将伊甸园去中的不再 被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存0区。若幸存0区满了,再对该区进行垃圾回收,然后移动到1区。那如果1区也满了呢??
幸存者区(Survivor space):0区,1区
老年区:
新生区经过多次GC仍然存回的对象移动到老年区。若老年区也满了,那么这个时候将产生 MajorGC(FullGC),进行老年区的内存清理 ,若老年区执行了Full GC 之后发现仍然无法进行对象的保存,就会产生OOM异常”OutOfMemoryError“。
如果一个实例对象在新生代 中,成功的在15次垃圾回收之后,就会移动到老年代中
2. java 栈(线程私有)
一个线程对应一个栈,每个方法在执行的同时都会创建一个栈帧(用户存储局部变量表,操作数栈,动态链接,方法出口等信息),不存在垃圾回收问题,只要线程一结束该栈就释放,生命周期和线程一致。
该区域规范了两种异常:
线程请求的栈深度大于虚拟机栈所允许的深度,并抛出StackOverFlowError异常
若虚拟机栈可动态扩展,当无法申请到足够内存空间时将抛出OutOfMemoryError,通过JVM 参数 -Xss指定栈空间,空间大小决定函数调用的深度
3. 方法区(线程共享)
类的所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。简单的说,所有定义的方法的信息都保存在该区域,静态变量 + 常量 + 类信息(构造方法/接口定义) + 运行时常量池都存在方法区中。
4.元数据区
元数据区取代了永久代(jdk1.8之前).本质和永久代相似,都是对JVM规范中方法区的实现,区别在于元数据区 不再虚拟机汇总,而是使用本地物理内存,永久代在虚拟机中,永久代逻辑结构上属于堆,但是物理上不属于堆,堆大小 = 新生代 + 老年代。 元数据区有可能发生OutOfMemory 异常
jdk6 以及之前:有永久代,常量池在方法区
jdk7 ,有永久代,常量池在堆上
jdk8之后,无永久代,常量池在元空间
元数据区的动态扩展,默认–XX:MetaspaceSize值为21MB的高水位线。一旦触及则Full GC将被触发并卸载没有用的类(类对应的类加载器不再存活),然后高水位线将会重置。新的高水位线的值取决于GC后释放的元空间。如果释放的空间少,这个高水位线则上升。如果释放空间过多,则高水位线下降。
5、程序计数器(线程私有)
记录当前执行的字节码指令的位置,也就是记录目前执行到了那一条字节码指令
6、本地方法栈(线程私有)
新生代和老年代的对象分配机制对象优先在eden分配
大对象直接进入老年代:字符串,数组,虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置的对象直接在老年代分配。这样做的目的是避免在Eden区以及两个Survivor区直接放生大量的内存复制
长期存活的对象将进入老年代
动态对象年龄判断机制:为了更好的适应不同程序的内存情况,虚拟机并不是永远要求对象的年龄必需达到某个固定的值(比如前面说的 15)才会被晋升到老年代,而是会去动态的判断对象年龄。如果在 Survivor 区中相同年龄所有对象大小的总和大于 Survivor 空间的一半,年龄大于等于该年龄的对象就可以直接进入老年代。
空间担保机制
在发生Minor GC 之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果成立,那么Minor GC 可以确保是安全的。如果不成立,则虚拟机会查看HandlerPromotionFailure设置值是否允许担保失败》如果允许,就是看看老年代的内存大小,是否大于之前每一次Minor GC后进入老年代的对象的平均大小。如果上面的步骤判断失败了,或者是-XX:-HandlerPromotionFailuer参数没设置,此时就会直接出发一次 FULL GC,就是对老年代进行垃圾回收,尽量腾出来一些内存空间,然后再执行Minor GC如果上面都判断成功了。此时进行Minor GC 有几种可能Minor GC 过后,剩余的存活对象的大小,是小于Survivor区的大小的,那么此时存活对象进入Survivor区域即可Minor GC过后,剩余的存活对象的大小,是大于Survivor区域的代销,但是小于老年代可用内存大小的,此时是直接进入来年代即可。Minor GC 过后,剩余的存活对象的,大于了Survivor区域的大小,也大于了老年代可用内存的大小。此时老年代都放不下这些存活的对象,就会发生”Handle Promotion Failure” 的情况,这个时候就会触发一次 Full GCJVM内存相关的集合核心参数-Xms:java堆内存的大小:通常情况下 -Xms 和 -Xmx 设置一样
-Xmx: java堆内存的最大大小
-Xmn: Java堆内存中的新生代大小,扣除新生代剩下的就是老年代的内存大小
-XX:PermSize: 永久代大小
-XX:MaxPermSize: 永久代最大大小
-XX:MetaspaceSize
-XX:MaxMetaspaceSize
-Xss: 每个线程的栈内存大小
对象分配流程对象访问方式虚拟机类加载机制什么时候会把
.class
字节码文件加载到虚拟机中?JVM对class文件是按需加载(运行期间动态加载),非一次性加载,见示例(启动需要加上参数:-verbose:class)
类加载时机
遇到new、getstatic、putstati 或 invokestatic 这4条指令时,如果类没有进行初始化,则需要先触发其初始化。生成者4条指令的java代码场景是: 使用new关键字实例化对象的时候、读取或者设置一个类的静态字段(被final修饰、已在 编译期把结果 放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候;使用java.lang.reflect 包的方法对类的进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。当初始化一个类的时候,如果没有发现其父类还没有进行过初始化,则需要先触发其父类的初始化当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法那个类),虚拟机会先初始化这个主类3.类加载过程
4.类与类加载器 : 类加载器 + 类 = 唯一
5.双亲委派机制
垃圾回收如何判断对象为垃圾对象
引用计算法在对象中添加一个引用计数器,当有地方引用这个对象的时候,计数器 + 1,当失效的时候,计数器 – 1 可达性分析法通过一些列的的称为”GC Root” 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GCRoots 没有任何引用链 相连时,则证明此 对象时不可用的
可做为GC Roors的对象:虚拟机栈(栈帧的本地变量表)中的引用对象,方法区中类静态属性的引用的对象,方法区中常量 引用的对象,本地方法栈中JNI引用的对象,
一句话总结: 只要你的对象被方法的局部变量、类的静态变量给引用了,就不会回收他们。
2.垃圾回收算法
标记清除
复制
标记整理
分代算法
3.垃圾回收器
Serial 和 Serial Old 垃圾回收器
分别回收新生代和老年代的垃圾对象。
工作原理: 垃圾回收的时候会停止大家自己写的系统的其他工作线程,让大家 系统直接卡死不动,然后让他们垃圾 回收,这个现在一般写后台 java 系统几乎不用。
ParNew 和 CMS 垃圾回收器
多线程回收垃圾
线程数量: 默认和CPU的核数一样
CMS 是用在老年代的垃圾 回收器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它而非常符合在注重用户体验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。初始标记: 标记出来所有GC Roots直接引用的对象并发标记:在运行期间可能会创建新的存活对象,也可能让部分存活对象失去引用,变成垃圾对象。在并发标记的时候,系统程序会不停的工作,他可能会各种创建出来新的对象,部分对象可能变成垃圾。需要对GC Roots进行深度追踪,因为老年代里存活的对象比较多。重新标记:在第二个阶段,一遍标记存活对象和垃圾对象,一边系统不停运行创建新对象,让老对象变成垃圾。所以在第二阶段结束之后,会有很多存活对象和垃圾对象,是之前没有标记出来的并发清除:并发清理。需要把垃圾对象从各种随机的内存位置清理掉,也是比较耗时的G1垃圾回收器
统一收集新生代和老年代,采用了更加优秀的算法和设计机制
G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征.
特点 :Java堆内存分为多个大小相等的Region。设置一个垃圾回收的预期停顿时间
监控工具与故障处理工具命令行 工具
jpsjstatjinfojmapjhatjstackhsdis2. jdk的可视化工具
jconsole
visualvm
Arthas:java诊断工具Btrace:故障分析工具GC日志和线程GC日志:gceasy
堆栈定位:fastthread