Java基础知识

java是一个面向对象的,静态类型,编译执行,有VM/GC和运行时的跨平台的高级语言。

一. 字节码技术

将写好的java文件编译成class

javac .\TestJvm.java

查看字节码

javap -c TestJVM

查看更详细的字节码

javap -c -verbose TestJVM

字节码的运行时结构

JVM是一个基于栈的计算机器。每个线程都有他所对应的线程栈,用于存储栈帧。每一次方法调用,都会创建一个栈帧。

栈帧由操作数栈,局部变量数组以及一个Class引用(也叫动态链接)组成。

  • 操作数栈:每个帧都包含了一个后入先出的栈,称为操作数栈。

  • 局部变量表:用于存放方法参数和内部定义的局部变量。局部变量表的容量以变量槽(Slot)为单位,一个Slot只能存放一个boolean、byte、char、shoert、int、float、reference或returnAddress类型的数据

  • Class引用:指向当前方法在运行时常量池中对应的class

二、JVM类加载器

类的生命周期

  1. 加载:找class文件
  2. 校验 :验证格式,依赖
  3. 准备 :静态字段,方法表
  4. 解析:符号解析为引用
  5. 初始化 :构造器,静态变量赋值,静态代码块
  6. 使用
  7. 卸载
类的加载时机
  1. 当虚拟机启动时,初始化用户指定的主类,就是启动执行的 main 方法所在的类;
  2. 当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类,就是 new

    一个类的时候要初始化;
  3. 当遇到调用静态方法的指令时,初始化该静态方法所在的类;
  4. 当遇到访问静态字段的指令时,初始化该静态字段所在的类
  5. 子类的初始化会触发父类的初始化
  6. 如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,

    会触发该接口的初始化
  7. 使用反射 API 对某个类进行反射调用时,初始化这个类,其实跟前面一样,反射调用

    要么是已经有实例了,要么是静态方法,都需要初始化
  8. 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的

不会初始化(可能会加载)

  1. 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化
  2. 定义对象数组,不会触发该类的初始化
  3. 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类
  4. 通过类名获取 Class 对象,不会触发类的初始化,Hello.class 不会让 Hello 类初始化。
  5. 通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触

    发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。Class.forName

    (“jvm.Hello”)默认会加载 Hello 类。
  6. 通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作(加载了,但是

    不初始化)

三类类加载器

从上到下依次是:

  • 启动类加载器(BootstrapClassLoader)
  • 扩展类加载器(ExtClassLoader)
  • 应用类加载器(AppClassLoader)

类加载器特点:

双亲委派、负责依赖、缓存加载

加载过程:如一个Hello.class文件,不考虑自定义加载器,首先会在AppClassLoader中检查是否已经加载过,如果加载过就不加载了。如果没有加载过,就会拿到父加载器,那么父加载器(ExtClassLoader)就会检查是否加载过,如果没有,就再往上,让BootStrapClassLoader检查是否加载过。

如果还是没有,因为他的上面已经没有父加载器了,那么他就开始自己加载,如果能加载,他就自己加载。不能加载,就下沉到子加载器去加载,一直到最底层,如果没有类加载器能加载就抛出异常ClassNotFoundException

添加引用类的几种方式

  1. 放到JDK的lib/ext下,或者-Djava.ext.dirs
  2. java -cp/classpath 或者将class文件放在当前路径
  3. 自定义ClassLoader加载
  4. 拿到当前执行类的ClassLoader,反射调用addUrl方法添加jar或路径
public class Test1 {

    public static void main(String[] args) throws MalformedURLException, NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
String appurl="file:/d:/logs/";
URLClassLoader classLoader = (URLClassLoader)Test1.class.getClassLoader();
Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addURL.setAccessible(true);
URL url=new URL(appurl);
addURL.invoke(classLoader,url);
Class.forName("Test2");
}
}

我将Test2.class文件放在d盘的logs文件夹下。

三、JVM内存结构

Jvm整体结构

可以看到,我们的JVM进程里面除了堆还有栈、非堆、JVM自身。而我们的操作系统里还有其他进程。

所以我们设置堆内存的时候,不能设置为机器的内存大小,如4G的机器千万不能把-Xms -Xmx 设置为4G,一般设置为机器内存的60%-70%。

JVM栈结构

栈:线程栈,也叫Java方法栈,每启动一个线程就会创建一个栈,如果使用了JNI方法,就会分配一个单独的本地方法栈。线程执行过程中,一般会有多个方法组成调用关系,如方法A调用方法B,每执行到一个方法,就会创建一个栈帧。

所有的原生对象类型(如int,long)和对象引用地址都在栈上存储。

JVM堆结构

堆:对象、对象成员以及类定义、静态变量都在堆上。

什么是JMM?

Java内存模型。明确定义了不同的线程之间,通过哪些方式,在什么时候可以看到其他线程保存在共享变量中的值;以及如何对共享变量进行同步。JMM规范的是线程间的交互操作。

从抽象上来看,JMM定义了线程和主内存之间的抽象关系。

四、JVM启动参数

JVM启动参数有如下几类:

  • 以-开头为标准参数,所有的 JVM 都要实现这些参数,并且向后兼容。如:++-server++

  • 以-D开头的,设置系统属性 如:++-Dfile.encoding=UTF-8++

  • 以 -X 开头为非标准参数, 基本都是传给 JVM 的,

    默认 JVM 实现这些参数的功能,但是并不保证所

    有 JVM 实现都满足,且不保证向后兼容。 可以使

    用 java -X 命令来查看当前 JVM 支持的非标准参 如:++-Xmx8g++

    数。

  • 以 –XX:开头为非稳定参数, 专门用于控制 JVM

    的行为,跟具体的 JVM 实现有关,随时可能会在

    下个版本取消。

  • -XX:+-Flags 形式, +- 是对布尔值进行开关 如:++-XX:+UseG1GC++

  • -XX:key=value 形式, 指定某个选项的值 如:++-XX:MaxPermSize=256m++

4.1 系统属性参数

-Dfile.encoding=UTF-8 -Duser.timezone=GMT+08

或者通过

System.setProperty("a","A100");设定,Linux上还可以通过a=A100 java XXX 设定。

4.2 运行模式
  1. -server:设置 JVM 使用 server 模式,特点是启动速度比较慢,但运行时性能和内存管理效率

    很高,适用于生产环境。在具有 64 位能力的 JDK 环境下将默认启用该模式,而忽略 -client 参

    数。
  2. -client :JDK1.7 之前在32位的 x86 机器上的默认值是 -client 选项。设置 JVM 使用 client 模

    式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或

    者 PC 应用开发和调试。此外,我们知道 JVM 加载字节码后,可以解释执行,也可以编译成本

    地代码再执行,所以可以配置 JVM 对字节码的处理模式:
  3. -Xint:在解释模式(interpreted mode)下运行,-Xint 标记会强制 JVM 解释执行所有的字节

    码,这当然会降低运行速度,通常低10倍或更多。
  4. -Xcomp:-Xcomp 参数与-Xint 正好相反,JVM 在第一次使用时会把所有的字节码编译成本地

    代码,从而带来最大程度的优化。【注意预热】
  5. -Xmixed:-Xmixed 是混合模式,将解释模式和编译模式进行混合使用,有 JVM 自己决定,这

    是 JVM 的默认模式,也是推荐模式。 我们使用 java -version 可以看到 mixed mode 等信息。
4.3 堆内存

-Xmx, 指定最大堆内存。 如 -Xmx4g. 这只是限制了 Heap 部分的最大值为4g。

这个内存不包括栈内存,也不包括堆外使用的内存。

-Xms, 指定堆内存空间的初始大小。 如 -Xms4g。 而且指定的内存大小,并

不是操作系统实际分配的初始值,而是GC先规划好,用到才分配。 专用服务器上需要保持 –Xms 和 –Xmx 一致,否则应用刚启动可能就有好几个 FullGC。

当两者配置不一致时,堆内存扩容可能会导致性能抖动。

-Xmn, 等价于 -XX:NewSize,使用 G1 垃圾收集器 不应该设置该选项,在其他的某些业务场景下可以设置。官方建议设置为 -Xmx 的 1/2 ~ 1/4.

-XX:MaxPermSize=size, 这是 JDK1.7 之前使用的。Java8 默认允许的Meta空间无限大,此参数无效。

-XX:MaxMetaspaceSize=size, Java8 默认不限制 Meta 空间, 一般不允许设置该选项。

-XX:MaxDirectMemorySize=size,系统可以使用的最大堆外内存,这个参数跟 -Dsun.nio.MaxDirectMemorySize 效果相同。

-Xss, 设置每个线程栈的字节数。 例如 -Xss1m指定线程栈为1MB,与-XX:ThreadStackSize=1m 等价

4.4 GC相关

-XX:+UseG1GC:使用 G1 垃圾回收器

-XX:+UseConcMarkSweepGC:使用 CMS 垃圾回收器

-XX:+UseSerialGC:使用串行垃圾回收器

-XX:+UseParallelGC:使用并行垃圾回收器

// Java 11+

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC

// Java 12+

-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC

4.5 分析诊断

-XX:+-HeapDumpOnOutOfMemoryError 选项, 当 OutOfMemoryError 产生,即内存溢出(堆内存或持久代)时自动 Dump 堆内存。

示例用法: java -XX:+HeapDumpOnOutOfMemoryError -Xmx256m ConsumeHeap

-XX:HeapDumpPath 选项, 与 HeapDumpOnOutOfMemoryError 搭配使用, 指定内存溢出时 Dump 文件的目录。

如果没有指定则默认为启动 Java 程序的工作目录。

示例用法: java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/ ConsumeHeap

自动 Dump 的 hprof 文件会存储到 /usr/local/ 目录下。

-XX:OnError 选项, 发生致命错误时(fatal error)执行的脚本。

例如, 写一个脚本来记录出错时间, 执行一些命令, 或者 curl 一下某个在线报警的 url.

示例用法:java -XX:OnError="gdb - %p" MyApp

可以发现有一个 %p 的格式化字符串,表示进程 PID。

-XX:OnOutOfMemoryError 选项, 抛出 OutOfMemoryError 错误时执行的脚本。

-XX:ErrorFile=filename 选项, 致命错误的日志文件名,绝对路径或者相对路径。

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1506,远程调试

4.6 JavaAgent

Agent 是 JVM 中的一项黑科技, 可以通过无侵入方式来做很多事情,比如注入 AOP 代码,执行统

计等等,权限非常大。这里简单介绍一下配置选项,详细功能需要专门来讲。

设置 agent 的语法如下:

-agentlib:libname[=options] 启用 native 方式的 agent, 参考 LD_LIBRARY_PATH 路径。

-agentpath:pathname[=options] 启用 native 方式的 agent。

-javaagent:jarpath[=options] 启用外部的 agent 库, 比如 pinpoint.jar 等等。

-Xnoagent 则是禁用所有 agent。

以下示例开启CPU使用时间抽样分析:JAVA_OPTS="-agentlib:hprof=cpu=samples,file=cpu.samples.log

JVM核心技术(第一篇)的更多相关文章

  1. JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇

    JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇 作为一个使用Java语言开发的程序员,我们都知道,要想运行Java程序至少需要安装JRE(安装JDK也没问题).我们也知道我们Java程序 ...

  2. 深入jvm虚拟机--第一篇 void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState tos_out) 函数

    今天第一次使用虚拟姐打断点,断点设置在了void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState t ...

  3. java核心技术第一篇之数据库基础

    01.数据库的概念: 1).数据库的概念:数据库(Database),就是存储数据的仓库. 2).作用:用来存储和管理大量数据的.内部采用了非常便于查询的机制来存储数据,能保证我们在大量数据的情况下 ...

  4. Eclipse插件开发 学习笔记 PDF 第一篇到第四篇 免分下载 开发基础 核心技术 高级进阶 综合实例

    <<Eclipse插件开发 学习笔记>>,本书由浅入深.有重点.有针对性地介绍了Eclipse插件开发技术,全书分为4篇共24章.第一篇介绍Eclipse平台界面开发的基础知识 ...

  5. JVM学习篇-第一篇

    JVM学习篇-第一篇 JDK( Java Development Kit): ​ Java程序设计语言.Java虚拟机.Java类库三部分统称为JDK,JDK是用于支持Java程序开发的最小环境** ...

  6. [转载] Android Metro风格的Launcher开发系列第一篇

    前言:从毕业到现在已经三年多了,回忆一下这三年基本上没有写过博客,总是觉得忙,没时间写,也觉得写博客没什么大用.但是看到很多大牛们都在写博客,分享自己的东西,所以嘛本着向大牛看齐,分享第一,记录第二的 ...

  7. Android Metro风格的Launcher开发系列第一篇

    前言:从毕业到现在已经三年多了,回忆一下这三年基本上没有写过博客,总是觉得忙,没时间写,也觉得写博客没什么大用.但是看到很多大牛们都在写博客,分享自己的东西,所以嘛本着向大牛看齐,分享第一,记录第二的 ...

  8. 第一篇 入门必备 (Android学习笔记)

    第一篇 入门必备 第1章 初识Android 第2章 搭建你的开发环境 第3章 创建第一个程序--HelloWorld 第4章 使用Android工具   ●Android之父 Android安迪·罗 ...

  9. Java Nested Classes(内部类~第一篇英文技术文档翻译)

    鄙人最近尝试着翻译了自己的第一篇英文技术文档.Java Nested Classes Reference From Oracle Documentation 目录 嵌套类-Nested Classes ...

  10. spring boot实战(第一篇)第一个案例

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   spring boot实战(第一篇)第一个案例 前言 写在前面的话 一直想将spring boot相关内容写成一个系列的 ...

随机推荐

  1. SpringBoot入门学习看这一篇就够了

    1.SpringBoot是什么? SpringBoot是一套基于Spring框架的微服务框架. 2.为什么需要SpringBoot 由于Spring是一个轻量级的企业开发框架,主要的功能就是用于整合和 ...

  2. Java中HashMap的源码分析

    先来回顾一下Map类中常用实现类的区别: HashMap:底层实现是哈希表+链表,在JDK8中,当链表长度大于8时转换为红黑树,线程不安全,效率高,允许key或value为null HashTable ...

  3. DAOS 分布式异步对象存储|架构设计

    分布式异步对象存储 (DAOS) 是一个开源的对象存储系统,专为大规模分布式非易失性内存 (NVM, Non-Volatile Memory) 设计,利用了SCM(Storage-Class Memo ...

  4. 20182217_刘洪宇 后门原理与实践 EXP2

    1.后门概念 后门就是不经过正常认证流程而访问系统的通道. 哪里有后门呢? 编译器留后门 操作系统留后门 最常见的当然还是应用程序中留后门 还有就是潜伏于操作系统中或伪装为特定应用的专用后门程序. - ...

  5. javascript 取自己

    var own=docment.currentScript;

  6. DFS 深搜专题 入门典例 -- 凌宸1642

    DFS 深搜专题 入门典例 -- 凌宸1642 深度优先搜索 是一种 枚举所有完整路径以遍历所有情况的搜索方法 ,使用 递归 可以很好的实现 深度优先搜索. 1 最大价值 题目描述 ​ 有 n 件物品 ...

  7. Egress-Assess-出口数据安全功能测试

    简介 Egress-Assess是一款用于测试出口数据检测功能的工具,该工具可辅助完成数据安全模型测试. 在各种情况下,我们的团队都会尝试从我们正在运行的网络中提取数据,并将其移至另一个位置以进行脱机 ...

  8. MySQL提升笔记(2):存储引擎盘点

    在前面我们了解了server层调用存储引擎层接口来完成sql的执行,使用存储引擎的好处是:每个存储引擎都有各自的特点,能够根据具体的应用建立不同存储引擎表. 需要注意的是,存储引擎是基于表的,而不是数 ...

  9. 安装maven工程报错"Failed to execute goal on project...Could not resolve dependencies for project..."

    我在qingcheng_interface中Lifecycle目录下执行install命令后报错"Failed to execute goal on project...Could not ...

  10. jdbcTemplate事务管理

    1.基于TransactionTemplate的编程式事务管理 Spring之路(39)–基于TransactionTemplate的编程式事务管理 本篇通过TransactionTemplate类, ...