一.历史
- 技术和时间点
- 1996,JDK1.0:虚拟机和AWT、Applet
- 1997,JDK1.1:内部类、反射、jdbc、jar
- 1998,JDK1.2:swing、三大分类(SE、EE、ME)、collection
- 2000年,JDK1.3,hotspot成为御用商用虚拟机。
- 2002,JDK1.4:正则、异常链、nio,.net框架的竞争加入
- 2004,JDK5:泛型、枚举、自动装箱等语法,还有juc。
- 2006,JDK6:开源、http的api、注解处理器,2009被收购。
- 2011,JDK7:sun被收购后的商业化探索
- 2015,JDK8:日期API、Lambda、永久代移除
- 2018,JDK11:Android遭大重,因为API有版权;放弃javaEE(含有servlet、JDbc等组件);出现OracleJDK商用模式。
- 2019,JDK12:RedHat接手历史版本维护,OracleJDK首次出现和openJDK不一样。
- 几个重要概念
- JCP(Java Community Process):主要由Java开发者以及被授权者组成,职能是发展和更新
- JEP(JDK Enhancement Proposals):由Oracle成立来管理新版本JDK的发布功能。
- 虚拟机
- JavaME的CLDC—如今只能在老人机里有市场
- JavaSE的HotSpot—如今已经融合了jrockit的监控,一家独大。
- apache和Dalvik:apache退出jcp组织;谷歌的Dalvik基于寄存器架构,所用的类库也不一样。
二.内存
-
1.程序计数器
- 概念:线程私有,唯一一个没有过oom的区域。
- 作用:记录程序运行指令下一跳内存地址——解决多线程恢复问题和顺序执行
-
2.栈
- 概念:方法栈帧,线程私有
- 栈帧组成:局部变量表、操作数栈、动态链接、方法出口。
- 局部变量表:进入方法时的大小即变量槽数量是确认的。
- 异常:栈溢出是StackOverflow,申请失败则是oom,hotspot不允许动态扩展。
-
3.本地方法栈
- 概念: hotspot实际上是本地和虚拟机栈合二为一实现的。
- 作用:是调用别的c语言的库函数,native方法存放在此区
-
4.方法区
- 落地实现:7是永久代8是元空间,线程共享的。
- 作用:存放类信息(类模板)、常量、静态常量、字符串常量。
- 永久代:8之后被取消,存放的是jar包class等元数据方便加载、以前跟老年代抢空间、静态类信息也存这。
- 元空间:存放类信息(类模板)
-
5.常量池
- 编译时规定常量池数据,也可以动态加入。8之后存在堆中
- 内容:字面量和符号引用和直接引用。
-
6.直接内存
- nio :操作java堆上的DirectByteBuffer对象作为这块内存的引用
- 0拷贝:绕过虚拟机堆空间,从直接内存复制到用户空间进行操作。
-
7.堆
- 理解:栈管运行引用,堆管空间——存的就是实例对象
- 并发方面:线程共享,但可以有线程私有的分配缓冲区
- 存有到方法区类模板的指针
8.对象的创建流程
- 分配空间:
- 指针碰撞法:适合内存规整,所以需要配合复制、标记清除压缩算法
- 空闲列表:适合零散,比如标记清除
- 本地线程缓冲区TLAB:解决多线程下的内存分配指针冲突,需要一段线程私有缓冲区。
- 设置对象头:确定属于哪个类的类指针、gc的年龄
- 锁状态、偏向id
- 句柄
三.垃圾收集
垃圾收集
- from(幸存者一区)和to区能交换——gc扫描eden和from存活去to
- gc回收15次不到的去老年代
- fullgc回收不行时报oom
垃圾标记算法
- 引用计数器:计算机维护引用(已经弃用),因为无法解决循环引用。只有flashplayer、com等地方使用。
- 可达性分析算法:gcroots跟对象,垃圾回收检查它拥有的引用链进行回收。
- finalize():只会在对象第一次被回收时被执行一次。
- 作用:对c++析构函数的一种妥协,开销极大,已经弃用。
垃圾收集算法
- 复制:年轻代复制的from到to,优点是不会产生内存碎片,缺点是耗空间(预留两份空间),to满去old。
- 标记清除:在survive区标记存活的清除可回收的,缺点是速度要扫描2次先标记再回收,会严重耗时,而且会产生碎片。
- 标记压缩:标记清楚后再压缩一样腾出空间——缺点是压缩一样要时间
四.调优和工具
调优
- 针对heap调优runtime对象表示运行时内存
- 调jvm大小:xms64/1,xmx4/1,生产环境配一样防止争抢出现
- 永久代:可调permmaxsize
- eden和old:默认比例8:1:1可调比例
- gc日志:记录回收多少内存
工具
- jps
- 可视化:
- Jconsole:
五.类加载
Class文件结构
- 概述:基于《虚拟机规范》级别的代码,可以由多种语言实现。
- 文件格式:类似于c语言结构体,类型只有无符号和表。
类加载时机
- 6种情况下:new、reflect包下的类方法、静态变量、静态方法、父类初始化、主类初始化
类加载过程
- 加载
- 通过全限定名读取二进制流文件
- 连接
- 初始化
类加载器
- 三大加载器:层层调用的先调用底层的(沙箱安全)
- bootstrap(c++):加载底层的类——rt.jar包启动类加载的包
- extclassloader:javax包——java写的
- appclassloader:自己编写的类的加载器
- 双亲委派:委派给父类加载器去加载类
六.java内存模型(jmm)
- 为了实现多线程——将物理上的内存分为工作内存(也是在堆里)和主内存。
本文作者为byzhj,转载请注明。