标记算法
引用计数法
无法检测出循环引用,导致内存泄漏1
2
3
4
5
6
7
8
9
10
11
12public class memleak {
public memleak childNode;
}
class problem{
public static void main(String[] args) {
memleak o1 = new memleak();
memleak o2 = new memleak();
// 循环引用
o1.childNode = o2;
o2.childNode = o1;
}
}
可达性算法
遍历所有GC Root引用链 不可达的就是垃圾。
GC Root 栈帧中的本地变量表 (局部变量)
方法区中常量引用/类静态属性引用对象 (类中的常量对象)
本地方法栈中JNI(Native方法)的引用对象。
活跃线程引用对象。
回收算法
标记清除算法
用可达性找到垃圾,再遍历一遍,删掉和去标记。
缺点:不移动对象。只对不存活的对象删除。 会产生内存碎片。
复制算法 (半区内存回收)
对象存活率低的场景(因为存活的很少,需要复制的少)(年轻代)
分为对象面和空闲面, 活得从对象面复制到存活面, 内存清除。
标记整理算法
适用于存活率高的场景(老年代)
先标记,移动所有存活对象到前面,然后吧末端全部回收。
分代收集算法
只有年轻代Minor GC(复制算法)和老年代Full GC。
年轻代有3个区 Eden:from Survivor:to Survivor = 8:1:1
把Eden和from存活的复制到to区,并且存活对象年龄+1。
年龄阈值-XX:MaxTernuringThreshold
(或者年轻代放不下了或者对象很大(-XX:+PretenuerSizeThreshold
)))之后放到老年代
Full GC 老年代用标记清理/整理的时候一般年轻代也要整理,所以叫Full GC
1)老年代空间不足
2)使用GMS GC 出现……
3)升级到老年代大于老年代剩余空间
4)System.gc()
5) 使用RMI进行RPC或管理的 JDK应用 每小时一次Full GC
G1收集器
堆划分成多个Region
引用类型
java 将其细分为四种:类、接口、数组类和泛型参数。由于泛型参数会在编译过程中被擦除(我会在专栏的第二部分详细介绍),因此 Java 虚拟机实际上只有前三种。在类、接口和数组类中,数组类是由 Java 虚拟机直接生成的,其他两种则有对应的字节流。
说到字节流,最常见的形式要属由 Java 编译器生成的 class 文件。除此之外,我们也可以在程序内部直接生成,或者从网络中获取(例如网页中内嵌的小程序 Java applet)字节流。这些不同形式的字节流,都会被加载到 Java 虚拟机中,成为类或接口。
对于数组类来说,它并没有对应的字节流,而是由 Java 虚拟机直接生成的。
对于其他的类来说,Java 虚拟机则需要借助类加载器来完成查找字节流的过程。
除了启动类加载器之外,其他的类加载器都是 java.lang.ClassLoader 的子类,因此有对应的 Java 对象。这些类加载器需要先由另一个类加载器,比如说启动类加载器,加载至 Java 虚拟机中,方能执行类加载。
双亲委派模型
双亲委派模型。每当一个类加载器接收到加载请求时,它会先将请求转发给父类加载器。在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。
类加载器
Java 9 引入了模块系统,并且略微更改了上述的类加载器1。扩展类加载器被改名为平台类加载器(platform class loader)。Java SE 中除了少数几个关键模块,比如说 java.base 是由启动类加载器加载之外,其他的模块均由平台类加载器所加载。
jmx链接 远程tomecat配置Catalina.sh加上java_opt里的jmx端口
本机virtlalVM直接输入远程ip:端口就能监控了
27个点 内存占20G
堆内存-Xmx12m
https://www.jianshu.com/p/1b1c998c4448
jstack 发现死锁 jstack pid > out.txt
https://toutiao.io/posts/1ogbep/preview
打印所有工作线程 包括析构Finalizer,JIT还有debug的
线程状态有6个
javap 字节码指令
1 | 用法: javap <options> <classes> |
JVM是基于栈的架构:指令短,指令数多
一般x86是基于寄存器的架构:指令长,指令集小
bytecode-viewerjava -XX:MaxHeapSize=734003200 -jar .\Bytecode-Viewer-2.9.11.jar
jclasslib bytecode viewer
jstat 查看类加载/GC/JIT编译信息
jinfo 查看运行中的jvm参数
1 | jinfo -flag MaxHeapSize 1972 |
打印进程Non-default参数(被赋值过的)1
jinfo -flags 1972
1 | Attaching to process ID 1972, please wait... |
jps
jps官网1
2
3
4jps -l
5392 sun.tools.jps.Jps
1972 org.jetbrains.jps.cmdline.Launcher
6500
JVM参数
1.java -help
XX参数(JVM调优和Debug)
Boolean类型
格式:-XX:[+-]<name>
启用或禁用name属性
启用CMS垃圾回收器-XX:+UseConcMarkSweepGC
启用G1垃圾回收器-XX:+UseG1GC
非boolean kv类型
格式:-XX:<name>=<value>
GC最大停顿时间-XX:MaxGCPauseMillis=500
-Xmx
-Xms
-Xms
等价于-XX:InitialHeapSize
-Xmx
等价于-XX:MaxHeapSize
-Xss
线程堆栈大小
X参数(非标准化参数)各个版本可能会变 不常用
java代码是解释执行的,JIT编译信息 即时编译 java代码转化成本地代码-Xint
完全解释执行(不转换成本地代码-Xcomp
第一次就编译成本地代码-Xmixed
混合模式JVM自己决定是否将java代码转本地代码
mixed mode:1
2
3
4java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
解释模式:1
2
3
4java -Xint -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, interpreted mode)
编译模式:1
2
3
4java -Xcomp -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, compiled mode)
堆外内存
64位的JVM 寻址空间
类装载器
1 | /* 只有jvm能创建 |
- 装载:(磁盘->内存)
1)取得类的二进制流:
装载器ClassLoader
读入java字节码装在到JVM
2)放到方法区
3)在堆中生成java.lang.Class对象 封装方法区的数据结构 - 链接:
1.验证 符合jvm对字节码的要求
2.准备 为static final
静态变量 分配内存,并初始化默认值。(还没生成对象)
3.解析 符号引用转换成指针or地址偏移量(直接引用)(内存中的位置) - 初始化:静态变量赋值(用户赋值)
<clint>
lang.NoSuchFiledError
最终结果是堆区的class对象,提供了访问方法区的接口(反射接口)
主动使用6种
1.创建类实例2.读写静态变量3.调用静态方法4.反射Class.forName 5.初始化类的子类 6.启动类
其它都是被动使用,都不会类初始化
jvm用软件模拟java字节码的指令集
jvm规范定义了:returnAddress
数据类型 指向操作码的指针;
输出整数的二进制1
2
3
4
5
6
7
8
9public static void main(String[] args) {
int a = 6;
//0x80000000表示最高位为1的数字
for(int i =0;i<32;i++){
//取出a的第一位 //无符号右移( >>> )
int t = (a&0x80000000>>>i)>>>(31-i);
System.out.print(t);
}
}
public native String intern();
运行期间放入常量池