JVM相关知识点总结

类加载
  • 加载时机
    使用new实例化对象时读取和设置类的静态变量,调用静态方法等;
    反射;
    初始化类先初始化父类;
    main所在的类;
    通过子类调用父类静态变量,不会初始化子类;
    定义对象数组或者集合,不会触发初始化该类;
    引用一个类的静态常量(必须为字面值常量,如,p s f int a = 1可, 而a = random.next则不可)不会初始化类;

  • 加载
    通过类全限定名获取类的二进制字节流;
    将字节流代表的静态数据结构转换为运行时结构;
    生成class对象,作方法区各种数据访问入口;

执行引擎

JAVA的解释器配和即时编译混合使用是半编译半解释语言;

  • 解释执行: 运行时候,针对字节码,通过解释器解释后执行;

  • 编译执行: 编译为计算机识别的语言后执行;

即时编译(JIT):

运行过程中通过编译器编译优化,缓存,直接生成机器码,执行;

三种模式,字节码解释器,模板解释器,混合模式;提升性能原因:运行期的热点代码编译和缓存;

  • 字节码解释器(如C1) 运行前期,收集信息少,编译优化少,生成代码执行效率较模板解释器编译后低;

    java字节码 -> c++代码 -> 计算机可识别的硬编码

  • 模板解释器(如C2) 运行一段时间,收集信息多,编译优化点多,生成代码执行效率高,优化多

    java字节码 -> 硬编码

逃逸分析:
JIT一种重要技术,根据变量作用域是否只在方法内,并且没有赋值给变量外的变量,就不会发生逃逸,如:局部变量,方法参数,相反则可能会发生逃逸;

  • 栈上分配:
    jvm动态判断不会逃逸对象是否直接在栈上分配内存,这样对象随着方法出栈销毁,减少gc次数,提高程序执行性能,一般针对高频、高量、低容量的引用对象:
  • 同步消除:
    分析不会逃逸对象,如 果不会被其他线程访问,编译优化去除同步;
  • 标量替换:
    标量:简单理解为java基本数据类型,不可再分割,聚合量:如:对象
    分析对象如果不会被外部访问,使用标量替换对象的成员变量,直接在栈上或者寄存器分配空间,如:用 20 替换 user.age(age=20);

对象

对象结构
  • 对象头
    MarkWord:占8B,存放对象运行时数据,如:hashcode,锁标志,gc年代,gc标志等;
    类型指针:指针压缩或32位:4B,否则8B,指向方法区的instanceKlass对象,用于表示属于哪个类实例;
    数组长度:只有数组才有,占4B;

  • 实例数据
    存放对象成员变量信息,包括父类继承;

  • 对齐填充
    8B倍数,不够0填充;

创建方式
  • new;
  • 反射
    clazz.newInstance(),
    User.class.getConstructor(Integer.class).newInstance(123))
  • clone,不会调用构造器;
  • 反序列化,不会调用构造函数;
创建过程

1.类加载检测
虚拟机接受new指令,根据指令参数去常量池定位这个类的符号引用,如果没有找到则加载这个类;
2.分配内存
在类加载的时候对象的大小就已经确认,通过指针碰撞或者空闲列表的方式给对象分配内存

  • 指针碰撞 内存规整
    通过一个指针指向内存使用的区域与未使用的区域的分界值,分配内存时中间值指针向未使用区域移动需要分配对象大小的长度;
  • 空闲列表 内存不规则
    jvm维护一个记录内存空间中可用的部分,分配内存时,在列表里寻找一个分配;
  • 并发分配内存安全
    因为堆是线程公用所以分配对象内存存在多线程竞争问题,因此分配内存时通过自旋CAS的方式设置,但是自旋会消耗处理器性能,因此每个线程会有一个位于Eden区初始默认1%大小的本地内存(TLAB),对象优先在本地内存中分配;

3.初始化0值
内存分配完成后,jvm将分配到的内存基本数据类型赋0值,引用类型赋null值;
4.设置对象头
包含类型指针,hashcode,gc信息,锁信息等;
5.执行<init>方法,完成对象创建
init方法在编译时生成,在创建对象是执行,所以称为实例构造器(clinit在类加载时候执行,所以称为类构造器),执行顺序是:

  • 父类变量初始化;
  • 父类代码块;
  • 父类构造函数;
  • 子类变量初始化;
  • 子类代码块;
  • 子类构造函数;
对象访问

1.句柄
将堆中的一块区划分出来作为句柄池,引用类型指向就是句柄池地址,句柄包含对象的实例对象指针和类型指针;
优点是对象的移动只需改变句柄中对象指针,而不需要改变引用地址;
缺点是多次寻址,性能较低;
2.直接指正(Hotspot使用)
引用类型指向就是对象的内存地址;
优点是直接寻址,效率高;
缺点是对象移动指针也要随之改变;

多线程程序计数器;

方法运行,栈:局部变量表,操作数栈...,方法执行过程;

堆(物理内存的1/64-1/4),内存分配,一次GC过程;

分配比例:

  • 新生代 1/3
    Eden区 8/10
    From区 1/10
    From区 1/10
  • 老年代 2/3

GC

一般情况对象会分配在新生代,在jdk1.8中默认的垃圾回收器为 parallel scavenge,他是多线程并行的垃圾收集器,因其设计理念为吞吐量优先,又称吞吐量优先收集器,吞吐量 = 代码执行时间/(代码执行时间+垃圾回收时间),采用的是复制算法;
1.8在老年代默认的垃圾回收器为Parallel Old,他并行并行的标记-整理算法;

1 触发
当创建对象的某一时刻,eden区全部挤满后就会触发Monitor GC;
2 GC前判断
老年代可用空间是否大于新生代所有对象,是则进入MonitorGC,否则触发老年代空间分配担保规则(如果配置了的话),

  • 老年代剩余大小,大于历次MonitorGC后剩余,进行MonitorGC,
  • 否则,进行FullGC;

3 MonitorGC

  • 通过标记阶段后将判断eden区和from区存活对象是否超过to区大小,不超过则全部移动到to区,清空eden和from区,原to区转换为from区;
  • 超过to区总大小,将全部存活对象年龄+1放入老年代,年龄超过15(默认)的全部加入老年代;
  • 默认年龄可以设置,最大为15,对象GC年龄是存在于对象头的MarkWord里的ObjerHeader里的4个bit位存放,其最大只能到15;

4 OOM FullGC后任然放不下剩余对象;

垃圾回收算法等;

垃圾判断算法
引用计数算法
记录对象被引用的次数,被其他对象引用计数+1,引用失效计数-1,计数为0,表示可回收,缺点是循环引用的对象无法被回收;
可达性分析算法
通过GC Roots对象作为起点,向下搜索引用链,无法达到的对象被认为可回收;

可作为GC Roots的对象:
正在被调用方法的栈帧中指向堆中的对象的参数,局部变量,临时值等;
jvm中的静态变量指向的对象;
3.正在被被加载的类;
4.运行时常量池中的引用型常量;
5.字符串常量池的引用;

垃圾回收算法
标记-清除算法(基础算法)
分为标记阶段清理阶段;缺点:标记和清理阶段需要stw,且效率不高,另外清理后会产生内存碎片,可能会导致无法获取连续内存分配给较大对象,非内存空间不足;
标记-复制算法(解决内存碎片)
分为标记阶段复制阶段清理阶段;将内存分为两块,每次使用其中一块,标记后将存活对象复制到未使用内存块,清理原内存块;
优点:无内存碎片,空闲内存时连续的不需要使用空闲列表分配对象,提高了效率;
缺点:空间浪费,每次只能使用一半的空间,对存活率高的对象,每次gc都需要进行复制操作,因此复制算法只适用于生命周期短的对象区域的回收,如新生代的gc算法;
标记-整理算法
分为标记->清除->整理三个阶段;类似标记清理算法,只是在标记后将存活对象向一端移动,清理调边界外的所有对象;
优点:无内存碎片,空间利用高;
缺点:性能较低;

jvm调优,工具,命令,含义;

常用命令
jps 线程pid
jstat class 加载类数量 gc次数等
jstack 看线程相关信息
jmap 看堆内存相关信息
频繁Full GC处理流程
1.查看GC日志,jvm启动参数加gc日志,分析gc;
2.dump GC日志:jmap -dump:format = b,file=文件名.hprof pid;
3.jvisualvm分析;
CPU高处理流程
1.top找到占用CPU最高的进程pid;
2.top -H -p pid找到该进程中占最高的线程;
3.线程id转化为16进制,用jstack 进程id |grep 16进制线程id -A 30 >> 文件名.dump 获取线程dump文件,分析代码问题;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351