虚拟机规范
https://docs.oracle.com/javase/specs/index.html
操作系统不识别字节码指令,虚拟机将其编译为机器指令
第一次编译将代码编译成字节码
第二次将字节码编译成机器指令并缓存进方法区
类加载器分类:启动类加载器,拓展类加载器,应用类加载器
双亲委派机制:
沙箱安全:
GC发生在方法区和堆
年轻代:复制算法,幸存者0-1区
eden区满时触发第一次GC(Yong GC),把活着的对象拷贝到SurvivorFrom区,当eden区再次触发GC(Full GC)的时候,会扫描Eden区和from区进行垃圾回收,经过这次回收还活着的复制到To区,对象年龄+1
复制次数到达15次还活下来的存入老年代
优点:无内存碎片
缺点:浪费空间
标记清除:mark–>sweep
优点:
缺点:会产生磁盘碎片
标记压缩:
缺点:移动对象需要成本
分代收集:
GCroot:
1.垃圾回收的时候如何确定垃圾?什么是GC Roots
可达性分析算法:从GC Roots对象向下搜索,如果遍历对象到GC Roots没有任何引用,则说明此对象不可用
2.那些对象可以作为GC Roots

GC Roots对象

JVM调优
标配: -version
-X:
-XX:+/- 开启关闭
查看jvm参数细节
jps -l
jinfo
jinfo -flag PrintGCDetails 15460是否开启
K V 设值
-XX:MetaspaceSize=
-XX:MaxTenuringThreshold=15
永久区几乎不会被回收,但不是不回收
只是回收的条件比较苛刻

虚拟机栈 局部变量,操作数栈,动态链接
java指令是基于栈设计的
每个线程创建时都会创建一个虚拟机栈
》线程私有
》保存的一个个栈帧

方法与栈帧一对一
方法执行:
1.正常结束
2.抛异常
javp -v xx.class 此处没有分号
反编译时,方法需是public得
返回值是int ireturn
方法虽然是void,但是可以写return,底层指令是存在的
47:栈帧的内部结构
一共五部分
局部变量表+操作数栈的大小影响单个栈帧的大小,单个栈帧的大小影响栈的大小,以及何时出现异常
48:局部变量表

编译器确定,一但确定不会被更改

Specific info
java代码 与字节码指令的对应关系 Slot 变量槽
占两个变量槽时,使用起始索引

静态方法中不能引用this,因为this也是一个变量不存在与当前方法的局部变量表中
变量的分类

操作数栈Operand Stack
栈访问数据只能通过入栈出栈来访问
上来放的就是1的位置,因为非静态方法,0放入this
i++和++i区别

栈顶缓存
将栈顶元素缓存到CPU中,提高执行引擎效率
动态链接与常量池

大部分字节码质量在执行的时候,都需要常量池的访问
指向运行时常量池的方法引用

方法的绑定机制
静态链接:编译期可确定

动态链接:编译期无法确定

早期绑定:

晚期绑定:

方法调用指令区分虚方法与非虚方法

invokeinterface 虚方法
invokedynamic指令 java7
动态类型语言vs静态类型语言

java仍然是静态的
方法重写本质

虚方法表
非虚方法不需要,因为已经确定了哪个方法
方法返回地址

本地方法接口,本地方法库

一个进程对应一个jvm实例,一个jvm实例对应一个运行时数据区,包含多个进程所以堆方法区共享
jvm启动的时候就被创建了,大小也就确定了
物理上不连续,逻辑上连续
TLAB是私有的

几乎所有的对象实例都是这里分配内存
GC频率过高,影响用户线程,stop the world
堆得细分结构

分代收集
jvisualvm

-Xms: X 参数
ms :memory start
查看某个进程或服务的GC情况
jps
jmap -heap 2082460

对象分解过程

YGC STW

对象分配 老年代 ↓

Promotion 晋升

from 区存在垃圾回收,但不触发minor Gc
养老区的Major Gc都无法保存的对象触发OOM
minor GC老年代回收Full gc还是整堆回收

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
ArrayList<MessageServiceImpl> list = new ArrayList<MessageServiceImpl>();
while (true){
list.add(new MessageServiceImpl());
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Minor GC会触发STW

内存分配自适应
TLAB:Thread Local Allotion Buffer 线程本地分配缓冲区

堆空间一定是共享的吗?

TLAB是线程私有的
堆空间的参数设置
堆是分配对象的唯一选择吗?
对象经过逃逸分析后并没有逃逸出方法的话,有可能优化成栈上分配
线程私有的,无同步执行可能
优化也是最终希望减少GC
如何快速判断是否发生逃逸分析,看new的对象是否有可能在方法外被调用

同步省略 锁销除
标量替换
逃逸分析本身也非常耗时

如何解决OOM

方法区的内部结构

涉及类得加载器也存在与方法区
记录方法信息的各个信息
异常信息
运行时常量池:包含字面量,类型,属性,方法的符号引用
字节以符号出现
#15 都是使用常量池里的
“count =” +count 底层会new StringBuilder
运行时常量池:动态性,字节码加载时的动态表现形式
方法区的演进

jvm分区
jvm分区
jvm分区
jvm分区
1
http://openjdk.java.net/jeps/122
jvm分区
jvm分区
1
2
3
Motivation
This is part of the JRockit and Hotspot convergence effort. JRockit customers do not need to configure the permanent generation (since JRockit does not have a permanent generation) and are accustomed to not configuring the permanent generation.
因为别人没有 我也没有

为什么要替换元空间?

1.永久代设置空间大小很难确定,动态还是不动态都很难
2.对永久代调优很困难

为什么字符常量池和静态变量发生了变化?

因为永久代回收效率比较低,当创建大量字符串的时候,回收效率低,导致内存不足

jvm分区
jvm分区

方法区存在垃圾回收,只不过是回收的条件比较苛刻

对象实例化的几种方式

jvm分区
jvm分区

给对象的属性赋值的操作
1.属性的默认初始化
2.显示初始化
3.代码块初始化
4构造器初始化
既有解释器又有编译器,结合运行
机器码 指令 汇编
即时编译器
热点代码探测方式:依执行频率而定 需要编译为本地代码的
只有在server模式下
分层编译
JDK10 新增编译器 Graal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
String str=new String("good");
char[] ch={'t','e','s','t'};

public void change(String str,char ch[]){
str="test ok"
char[0]=b;
}
public static voud main(String[] args){
StringExer ex=new StingExer();
xe.change(ex.str,ex.ch);
sysout(ex.str)//good
sysout(ex.ch)//best
}
10万行数据
public class GenerateString{
public void main(String[] args){
FileWriter fw=new FileWriter(word.txt);
fori100000
int length=(int)(Math.random()*(10-1+1)+1);
fw.write(str.getString(length)+"\n")
}
fw.close;

}

什么是双亲委派?
如果一个类加载器收到了加载某个类的请求,则该类加载器并不会去加载该类,而是把这个请求委派给父类加载器,每一个层次的类加载器都是如此,因此所有的类加载请求最终都会传送到顶端的启动类加载器;只有当父类加载器在其搜索范围内无法找到所需的类,并将该结果反馈给子类加载器,子类加载器会尝试去自己加载。
为什么要用双亲委派?
如果不是同一个类加载器加载,即时是相同的class文件,也会出现判断不想同的情况,从而引发一些意想不到的情况,为了保证相同的class文件,在使用的时候,是相同的对象,jvm设计的时候,采用了双亲委派的方式来加载类。
如何打破双亲委派?

通过自定义加载器的过程,我们知道,实现自定义的classloader,需要重新loadClass以及findClass
为什么要打破双亲委派?
主要处于安全性,防止核心类库的类被改写。你要是随便写一些基础String Object 那jvm就乱套了

jvm分区
jvm分区

对象是否被回收 经历两次标记过程
MAT Jprofiler

memory Analyzer
http://www.eclipse.org/mat
jps
jmap -dump:format=b,live,file=test1.bin 14036