jvm调优
一、代码是怎么跑起来的
首先我们应该知道代码是怎么跑起来的。一般我们写完java代码都是后缀为“.java”后缀的代码,然后打成jar包或者war包部署在服务上,打包的过程中,“.java”文件就被编译成了“.class”文件
而jvm想将字节码文件运行起来,就需要先加载进来。
二、类加载机制
类加载过程
加载——》验证——》准备——》解析——》初始化——》使用——》卸载
我们在用到这个代码的时候,才会加载
验证就是看看字节码文件的内容是否符合jvm规范
准备就是为一些被static修饰的变量分配内存空间,并初始化值,如果加了final这个阶段也会复制
解析:解析就是符号引用替换为直接引用的过程。直接引用是可以找到这个对象的地址的。
初始化:赋值,初始化子类的时候要先初始化父类
三、双亲委派机制
java中有启动类加载器(核心类库)、扩展类加载器(libext)、应用程序类加载器(环境变量所指定的类,也就是写的java文件)、自定义类加载器(可与防止被人反编译)
启动类加载器——最上层
扩展类加载器——中间一层
应用程序类加载器——第三层
自定义加载器——最下面
就是说应用程序类加载器要加载的时候,他首先会委派自己的父类加载器去加载,最终传到顶层的类加载器去加载。
顶层加载不了的下沉。这样可以确保不同的类加载器可以加载到相同的object对象。
四、内存划分
堆内存
方法区
本地方法去
虚拟机栈
程序计数器:执行代码指令,因为我们写的代码,计算机是不认识的,字节码是计算机理解的语言,所以当字节码文件被加载后,是使用字节码执行引擎,来执行指令的。程序计数器就是记录当值执行的字节码指令的位置的。线程都会有自己的程序计数器。
五、新生代里存活的对象
大部分都是朝生即死的,比如局部变量引用的对象,在方法运行时,是存在的,方法弹栈以后就成垃圾数据了,被static修饰的静态变量往往存活时间长,会进入老年代。
六、JVM内存的几个核心参数
-Xms:Java堆内存的大小 一般将Xms和Xmx设置成一样的,因为如果不一样堆内存会有一个膨胀收缩的过程。
-Xmx:Java堆内存的最大大小
-Xmn:Java堆内存中的新生代大小,扣除新生代剩下的就是老年代的内存大小了
-XX:PermSize:永久代大小
-XX:MaxPermSize:永久代最大大小
-Xss:每个线程的栈内存大小
堆内存空间设为3g,新生代2g是比较合理的,如果新生代只有1g,扣除老年代的,那么yang GC会很频繁的。
七、JVM的对象
只要被局部变量或静态变量引用的对象都不会被回收。
八、JVM算法
复制算法的缺点就是压缩了内存
动态年龄判断,比如s0区里两个2岁的随想加起来已经超过了一半的内存空间,那么两岁的会进入老年代,1+2+3+4.。。+n的对象超过一半,大于N的对象会进入。
九、大对象
有一个JVM参数,就是“-XX:PretenureSizeThreshold”,可以把他的值设置为字节数,比如“1048576”字节,就是1MB。
十、Minor gc过后对象太多怎么办
比如eden区存活的对象太多,survivor区放不下,那么这些对象就要进入老年代。
所以有了空间担保规则
就是说survivor区放不下,但是老年代也放不下的话?怎么办,所以Minor gc前,jvm会先检查老年代可用空间是否大于新生代所有对象的综合。
如果不大于。就要设置一个参数,空间担保,可以看看老年代可用空间是否大于以前移入的平均大小。如果这个都小于就会Fall gc