JVM基础

java文件到内存的流程

.java源文件-->进行编译-->.class字节码文件.

字节码文件-->加载-->验证-->准备-->解析-->初始化-->使用-->卸载.

验证:验证文件格式/元数据/字节码/符号引用等.

准备:根据验证后的类信息初始化类结构变量.

解析:常量池符号替换成直接引用(因为多态).

初始化:执行类构造器<clinit>()生成class对象放到堆中.

双亲委派模型:当前类加载器需要加载xx类时不会自己直接去加载,而是尝试将加载这个类的任务向上传递交给父加载器去完成,如果父类加载器能加载则由父类加载器来完成而自己不会再去加载.(好处:外部想要替换jdk的系统类,篡改它的实现时,因为父类加载器已经加载过jdk的系统类,子类加载器不会再加载,从而能够一定程度上防止危险代码的植入)

JVM 内存模型

JVM内存模型分为堆,栈,方法区,本地方法区,程序计数器.

栈:分为局部变量表,操作数栈,动态链接,方法出口.

局部变量:用于存放int,long,short,float,double,char,byte八种基本数据类型数据,存放以变量槽(slot)为最小单位(32bit/位),double,long这两种基本数据类型需要两个slot存储,所以会出现线程安全问题; 基本数据类型存储数值本身,引用数据类型存储指向堆内存的引用指针.

操作数栈:可以理解为PC寄存器,作为用于存储计算的临时数据存储区,当CPU执行load指令时能将数据加载进入操作数栈.

动态链接:由于OOP思想中存在多态的概念使得编译器在编译源代码时无法确定对象类型,只有在运行时才能确定对象,指向常量池中方法的引用.

方法出口:记录方法结束时的出栈地址(正常执行结束的返回地址或者由于报错结束时的异常地址).

本地方法栈

本地方法栈:与虚拟机栈相似,但是本地方法栈是为虚拟机的Native方法提供服务;Hotspot将虚拟机栈与本地方法栈合二为一.

程序计数器

程序计数器:由于CPU在执行的时候会存在线程时间片切换的概念,所以CPU执行指令的时候是会中断的,程序计数器会记录当前线程执行停止的字节码指令位置(行号),以便于再次切换到该线程时能够恢复到正确的执行位置而避免重新执行.

方法区

方法区:存放运行时常量池,类信息.

堆:堆主要用来存储对象,堆包含年轻代与老年代.

年轻代:包含Eden区,Survivor0区,Survivor1区.

TLAB:Thread Local AllocationBuffer在Eden区为每个线程开辟一个缓冲空间,线程在创建对象时如果该缓冲区的大小能够承载对象大小则直接在该区域分配对象,能够避免多个线程同时创建对象时由于竞争同意块堆内存时产生的资源消耗.

垃圾回收的时候也主要回收堆.

垃圾回收

对象存活判断算法

引用计数法:对于每个对象都自带一个计数器,有对象引用自己时+1,取消引用时引用时-1.当计数器为0时该对象标记为垃圾可以被回收(但是会存在a,b相互引用导致循环问题造成内存泄露)

根可达算法:通过GCRoots(栈中变量/方法区静态变量/Monitor持有者对象/常驻异常对象/JVM内部引用/方法区常量)对象作为起始点向下搜索,搜索走过的路径被称为引用链条,当一个对象到GCRoots没有任何引用链时即根不可达时该对象则判断为不可用可以被回收.

垃圾回收算法

标记清除算法:将对象标记出来,然后进行清除其余对象/地址.(缺点,会产生大量的垃圾碎片)

标记复制算法:将内存分为两份,将用到的对象移到其中一份内存中,然后将另一半进行清除.(缺点,浪费大量内存).

标记整理算法:将用到的对象移到内存的角落,进行排列,然后将其余的内存进行清理.(缺点,需要移动对象,效率不是特别高).

垃圾回收GC

分代处理器

young: Serial串行 ParNew(并行) ParellelScavenge(并行)

old:CMS(并发) SerialOld(串行) Parellel Old(并行)

G1承上启下:逻辑分类物理不分带(整理+复制)

不分代回收GC器

Epsilon:无作用GC器,当你的程序不需要GC时可以选择使用该GC器.

ZGC(并发):整理+复制.

Shenandoah(并发):整理+复制.

GC回收时的一些概念

STW(Stop-The-World):在GC发生时,所有用户线程都需要挂起停止,对于用户而言就是整个程序卡住不能动了,直到等到GC完成用户线程才能重新恢复执行.

为什么需要STW.GC发生时,GC线程和用户线程操作的是同一块内存区域,如果用户线程不停止,GC线程前脚刚标记完一块区域,用户线程就在这块区域创建了一个对象,当回收的时候,可能这个对象还是存活的,那么就会导致该对象被清除了,对于业务来说会出现很大影响,存在线程安全问题.

记忆集:我们都知道在发生新生代GC时都会通过根可达算法先判断垃圾对象,之后再对非存活对象进行统一回收,但是如果有老年代对象引用了新生代对象,那么根据根可达算法的特性,年老代也会被加入扫描分哪位,这样下来一次新生代的GC代价太大。所以为了解决跨代引用的问题,在新生代引入了记录集的数据结构,记录从非收集区到收集区的引用指针集合,避免在通过根可达算法判断对象存活时把整个老年代加入扫描范围。

标量替换:使用标量替换聚合量(对象),对于一个对象进行分解,将其拆解成一个个小的标量的过程(需要先进行逃逸分析,不可逃逸的对象才能进行标量替换).

标量:不可分割的量,指基本数据类型和reference类型.

好处:1.能够节省堆内存,因为进行标量替换以后的对象可以在栈上进行内存分配.2.相对运行而言省去了去堆中查找对象引用的过程,速度会更快一点.3.因为是分配在栈上,所以会随着方法结束和线程栈的弹出自动销毁,不需要GC的介入.

逃逸分析:判断变量作用域是否存在于其他栈帧或者线程中.当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸,判断逃逸的方法被称为逃逸分析.

栈上分配:一般而言java对象创建处理都是会在堆上进行内存分配,但其实也不是所有的对象都会在堆中分配,有时候也能够在栈上进行分配.不过想要将对象在栈上进行分配,需要先开启标量替换以及逃逸分析.

决定一个对象能否在栈上分配的因素:1.对象能够通过标量替换分解成一个个标量.2.对象在栈帧作用域不可逃逸.

如果一个对象能够满足如上两点则代表该对象可以在栈上进行分配.

同步消除:通过逃逸分析对一个对象进行逃逸判断之后,如果该对象为线程级作用域不可逃逸时,则代表当前这个对象只会有一个线程可访问.如果当前这个对象是被作为同步锁对象的,那么JVM会在编译时消除加锁和解锁的代码.

决定能否同步消除(满足一个即可):1.当前对象被分配在栈上.2.当前对象无法逃出线程作用域.

直接引用:1.直接执行内存地址的指针.2.相对的偏移量(方法指针/指向实例变量).3.句柄池中间接指向内存地址的句柄.

指针碰撞:指针碰撞是java在为对象分配堆内存时的一种内存分配方式,一般适用于Serial和ParNew等不会差生内存碎片,堆内存完整的垃圾收集器.

分配过程:堆中已用分配内存和为分配的空闲内存分别会处于不同的一侧,通过一个指针指向分界点区分,当JVM要为一个新的对象分配内存时,只需把指针往空闲的一端移动与对象大小相等的距离即可.

空闲列表:与指针碰撞一样,空闲列表同样是java在为新对象分配堆内存时的一种内存分配方式,一般适用于CMS等一些会产生内存碎片,堆内存不完整的垃圾收集器.

完全点:无论是在GC中还是线程安全中都会出现安全点(SafePoint)这个概念,当我们需要阻塞一个线程时都需要在安全点停止,简单说安全点就是指当线程运行到这类位置时,堆对象状态是确定一致的,当前线程停止后,JVM可以安全地进行操作,如GC,偏向锁撤销等.

安全点的定义:1.循环结束的末尾段.2.方法调用功能之后.3.抛出异常的位置.4.方法返回之前.

当JVM需要发生GC,偏向锁撤销等操作时如果让所有线程到达安全点阻塞?1.主动式中断(JVM采用的中断方式):不中断线程,而是设置一个标志然后让每个线程执行时主动轮询这个标志,当一个线程到达安全点后,发现中断标志为true时就自己中断挂起.2.抢断式中断:先中断所有线程,如果发现线程未执行到安全点则恢复线程让其运行到安全点位置.

JVM调优的常用参数

目录

java文件到内存的流程

JVM 内存模型

垃圾回收

JVM调优的常用参数


  • -Xms:堆最少空间

  • -Xmx:堆最大空间

  • -Xss:虚拟机栈大小

  • -XX:NewRatio: Old/New的比例

  • -Xmn:年轻代大小,调整会影响老年代大小,官方建议为堆大小的3/8.

  • -XX:SurvivorRatio:调整Survivor区和Eden区的大小比例.

  • -XX:MaxMetaspaceSize:元空间最大大小,逻辑限制为物理内存上限.

  • -XX:PretenureSizeThreshold:大对象直接进入老年代的阈值(字节为单位)

  • -XX:MaxTenuringThreshold:进入老年代的分店年龄阈值.

  • -XX:TargetSurvivorRatio:动态年龄判断比例设置.

  • -verbose:gc:输出JVM的gc情况.

  • -XX:+PrintGCDetails:输出GC详细信息.

  • -XX:+PrintGCTimeStamps:输出GC的时间戳(以基准时间的形式)

  • -XX:+PrintTenuringDistribution:输出对象GC年龄信息.

  • -XX:+PrintHeapAtGC:在进行GC的前后打印出堆的信息.

  • -Xloggc:路径:日志文件的输出路径.

  • -XX:+UseG1GC:用G1垃圾收集器(其他垃圾收集器也是一样,更换名字即可).

  • -XX:+PrintCommandLineFlags -version:输出默认的垃圾回收器.

  • -XX:+PrintGC:在控制器输出GC信息.

  • -XX:+PrintTLAB:可以查看TLAB的使用情况.

  • -XX:+UseSpining:开启自旋锁.

  • -XX:MaxGCPauseMillis:设置每次年轻代垃圾回收最大的停顿毫秒数.

  • -XX:EliminateAllocations:开启标量替换.

  • -XX:+DoEscapeAnalysis:开启逃逸分析.

  • -XX:+EliminateLocks:开启同步消除.

  • -XX:+PrintEliminateAllocations:查看标量替换情况.

  • -server:代表以server模式运行虚拟机.

  • -clinet:代表以client模式运行虚拟机.

  • -XX:ThreadStackSize:设置线程栈默认大小.

  • -XX:-UseTLAB:开启TLAB线程本地空间.

  • -Xnoclassgc:关闭垃圾回收机制.

  • -XX:TLABWasteTargetPercent:TLAB与Eden区的占比.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值