JVM

标记算法

引用计数法

无法检测出循环引用,导致内存泄漏

1
2
3
4
5
6
7
8
9
10
11
12
public 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
用法: javap <options> <classes>
其中, 可能的选项包括:
-help --help -? 输出此用法消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示最终常量
-classpath <path> 指定查找用户类文件的位置
-cp <path> 指定查找用户类文件的位置
-bootclasspath <path> 覆盖引导类文件的位置

JVM是基于栈的架构:指令短,指令数多
一般x86是基于寄存器的架构:指令长,指令集小

bytecode-viewerjava -XX:MaxHeapSize=734003200 -jar .\Bytecode-Viewer-2.9.11.jar

jclasslib bytecode viewer

suanfaGC.jpg

jstat 查看类加载/GC/JIT编译信息

jstat官网

jinfo 查看运行中的jvm参数

1
2
3
>jinfo -flag MaxHeapSize 1972
-XX:MaxHeapSize=734003200
>jinfo -flag ThreadStackSize <进程号>

打印进程Non-default参数(被赋值过的)

1
>jinfo -flags 1972

展开代码
1
2
3
4
5
6
Attaching to process ID 1972, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=132120576 -XX:MaxHeapSize=734003200 -XX:MaxNewSize=244318208 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44040192 -XX:OldSize=88080384 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=D:/demo/algLearn -Dpreload.config.path=C:/Users/cecil/.IntelliJIdea2017.2/config/options -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Djava.net.preferIPv4Stack=true -Dio.netty.initialSeedUniquifier=1077334432047011613 -Dfile.encoding=GBK -Djps.file.types.component.name=FileTypeManager -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2017.2 -Didea.home.path=C:\Program Files\JetBrains\IntelliJ IDEA 2017.2.5 -Didea.config.path=C:\Users\cecil\.IntelliJIdea2017.2\config -Didea.plugins.path=C:\Users\cecil\.IntelliJIdea2017.2\config\plugins -Djps.log.dir=C:/Users/cecil/.IntelliJIdea2017.2/system/log/build-log -Djps.fallback.jdk.home=C:/Program Files/JetBrains/IntelliJ IDEA 2017.2.5/jre64 -Djps.fallback.jdk.version=1.8.0_152-release -Dio.netty.noUnsafe=true -Djava.io.tmpdir=C:/Users/cecil/.IntelliJIdea2017.2/system/compile-server/alglearn_d660bc04/_temp_ -Djps.backward.ref.index.builder=true -Dkotlin.incremental.compilation.experimental=true -Dkotlin.daemon.enabled -Dkotlin.daemon.client.alive.path="C:\Users\cecil\AppData\Local\Temp\kotlin-idea-4845382868272217760-is-running"

jps

jps官网

1
2
3
4
jps -l
5392 sun.tools.jps.Jps
1972 org.jetbrains.jps.cmdline.Launcher
6500

JVM参数

1.java -help

XX参数(JVM调优和Debug)

  1. Boolean类型
    格式:-XX:[+-]<name> 启用或禁用name属性
    启用CMS垃圾回收器
    -XX:+UseConcMarkSweepGC
    启用G1垃圾回收器
    -XX:+UseG1GC

  2. 非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
4
java -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
4
java -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
4
java -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
2
3
4
5
6
7
8
9
10
/* 只有jvm能创建
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
  1. 装载:(磁盘->内存)
    1)取得类的二进制流:
    装载器ClassLoader 读入java字节码装在到JVM
    2)放到方法区
    3)在堆中生成java.lang.Class对象 封装方法区的数据结构
  2. 链接:
    1.验证 符合jvm对字节码的要求
    2.准备 为static final静态变量 分配内存,并初始化默认值。(还没生成对象)
    3.解析 符号引用转换成指针or地址偏移量(直接引用)(内存中的位置)
  3. 初始化:静态变量赋值(用户赋值)<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
9
public 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();运行期间放入常量池