跨平台特性:软件层屏蔽底层指令差异。
JVM内存模型
JVM内存参数
元空间参数:
-XX:MetaspaceSize:原空间Full GC的初始阈值,默认21M;Full GC后收集器会调整该值,若释放大量空间,调小;若释放少量空间,调大。
建议:应用启动发生大量Full GC,通常是永久代或元空间发生了大小调整,一般设置MetaspaceSize = MaxMetaspaceSize > 初始值,对于8G物理内存,设置为256M。
-XX:MaxMetaspaceSize:元空间最大值,默认不限制(受限于本地内存大小)
JVM对象创建
1.类加载检查(是否已经加载类,否则先加载类)
2.分配内存:对象所需内存在类加载完成后便可确定。
--如何划分内存
----指针碰撞(默认使用)
----空闲列表
--并发分配
----CAS配上失败重试,分配内存空间动作原子性
----本地线程分配缓冲,内存分配按照线程划分在不同空间进行
3.初始化
4.设置对象头
HotSpot中,对象在内存中的存储布局:
--对象头
----存储对象自身运行时数据Mark Word(32位占4字节,64位占8字节)
------哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等
----Klass Pointer类型指针(开启指针压缩4字节,不开启则占8字节)
------指向类元数据的指针,确定对象是哪个类的实例
----数组长度(4字节)
------只有数组对象才会有
--实例数据
--对齐填充(对象大小为8的整数倍,不足时需要填充)
5.执行方法,属性赋值(程序员赋值),执行构造方法
指针压缩
--使用较大指针在主内存和缓存之间移动数据,占用较大带宽,同时GC也会承受较大压力
--JVM中,32位地址最大支持4G,可以通过对对象指针压缩,编码解码进行优化,使得jvm使用32位地址就可以支持更大的内存配置(不超过32G)
----堆内存小于4G时,不需要启用指针压缩,jvm会直接去除高32位,使用低虚拟地址空间
----堆内存大于32G时,指针压缩失效,出现A问题,所以堆内存不要大于32G为好
对象内存分配
--对象栈上分配:jvm通过逃逸分析确定对象不会被外部访问,将对象在栈上分配,对象随栈帧出栈而销毁,减轻垃圾回收压力
----对象逃逸分析:分析对象动态作用域,会不会被外部方法引用。
----标量替换:通过逃逸分析确定对象不会被外部访问,并且对象可以进一步分解时,JVM不会创建对象,而是将对象成员变量分解若干个被这个方法使用的成员变量代替,这些代替的成员变量在栈帧或寄存器上分配空间。
----标量和聚合量:标量就是不可被进一步分解的量,java基本数据类型都是标量;聚合量就是可以被进一步分解的量,比如java中的对象。
对象栈上分配依赖于逃逸分析和标量替换。
对象Eden区分配
对象在新生代Eden区分配,当Eden区没有足够空间进行分配时,触发一次Minor GC
--Minor GC/Yong GC:新生代垃圾收集。频繁,速度快。
--Major GC/Full GC:老年代,年轻代,方法区一起垃圾收集。速度慢。
--Eden和Suvivor默认8:1:1
大对象直接进入老年代
--为了避免大对象分配内存时的复制操作而降低效率
----大对象:需要大量连续内存空间的对象(比如字符串,数组),JVM参数可设置大对象大小。(只在Serial和Parnew收集器下有效)
长期存活的对象进入老年代
--第一次Minor GC后仍能存活,并且能被Suvivor容纳,移动到Suvivor中,将对象年龄设为1;这样反复当年龄增加到15(CMS默认6),将对象移入老年代中。JVM参数可调整年龄。
对象动态年龄判断
--希望将可能是长期存活的对象,尽早进入老年代。
--一般在Minor GC之后触发,Suvivor中一批对象总大小大于Suvivor容量的50%,此时大于等于这批对象年龄最大值的对象就可以直接进入老年代。
老年代空间分配担保机制
年轻代每次 minor gc 之前JVM都会计算下老年代 剩余可用空间
如果这个可用空间小于年轻代里现有的所有对象大小之和( 包括垃圾对象 )
就会看一个“
-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了
如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的 平均大小 。
如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾,
如果回收完还是没有足够空间存放新的对象就会发生"OOM"
当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发full gc,full
gc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM”