写点什么

架构师训练营第九周学习总结

用户头像
qihuajun
关注
发布于: 2020 年 08 月 02 日

JVM

JVM 组成架构

Java 是一种跨平台的语言,JVM 屏蔽了底层系统的不同,为 Java 字节码文件构造了个统一的运行环境。



字节码

Java 所有的指令有 200 个左右,一个字节(8 位)可以存储 256 种不同的指令信息, 个这样的字节称为字节码( Bytecode)。在代码的执行过程中,JM 将字节码解释执行屏蔽对底层操作系统的依赖,JVM 也可以将字节码编译执行,如果是热点代码,会通过 JIT 动态地编译为机器码,提高执行效率。

执行流程


编译流程



类加载器的双亲委托模型

低层次的当前类加载器,不能覆盖更高层次类加载器已经加载的类。如果低层次的类加载器想加载个未知类,需要上级类加载器确认,只有当上级类加载器没有加载过这个类,也允许加载的时候, 才让当前类加载器加载这个未知类



堆 栈

堆:每个 JVM 实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享

堆栈:JVM 为每个新创建的线程都分配一个堆栈。也就是说,对于一个 Java 程序来说它的运行就是通过对堆栈的操作来完成的。

Java 中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配, 也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的引用而已。

方法区 程序计数器

方法区主要存放从磁盘加载进来的类字节码,而在程序运行过程中创建的类实例则存放在堆里。程序运行的时候,实际上是以线程为单位运行的,当 JVM 进入启动类的 main 方法的时候,就会为应用程序创建一个主线程,main 方法里的代码就会被这个主线程执每个线程有自己的 Java 栈,栈里存放着方法运行期的局部变量。而当前线程执到哪一行字节码指令,这个信息则被存放在程序计数寄存器。



Java(线程)栈

所有在方法内定义的基本类型変量,都会被每个运行这个方法的线程放入自己的機中线程的栈彼此隔离,所以这些变量一定是线程安全的。

线程工作内存 & volatile

Java 内存模型规定在多线程情况下,线程操作主内存変量,需要通过线程独有的工作内存拷贝主内存变量副本来进行。

被 volatile 修饰的共享变量:

  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

  • 禁止进行指令重排序。

JVM 垃圾回收

把堆中的已经不再被使用的对象清理掉。

通过一种可达性分析算法进行垃圾对象的识别,具体过程是:从线程栈帧中的局部量,或者是方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些被标记的对象是否引用了其他对象,继续进行标记,所有被标记过的对象都是被使用的对象,而那些没有被标记的对象就是可回收的垃圾对象了。

回收方法

  • 清理:将这些垃圾对象占用的内存空间标记为空闲记录在一个空闲列表里,当应用程序需要创建新对象的时候,就从空闲列表中找一段空闲内存分配给这个新对象

  • 压缩:从堆空间的头部开始,将存活的对象拷贝放在一段连续的内存空间中,那么其余的空间就是连续的空闲空间

  • 复制:将空间分成两部分,只在其中一部分创建对象,当这个部分空间用完的时候,将标记过的可用对象复制到另一个空间中

分代垃圾回收



垃圾回收器算法



G1 垃圾回收



Java 启动参数

标准参数

所有 JVM 都必须实现的参数

  • 运行模式 -server -client

  • 类加载路径 -cp -classpath

  • 运行调试 -verbose

  • 系统变量 -D

非标准参数

默认 jvm 实现这些参数,但不保证所有 jvm 都实现

  • -Xms 初始堆大小

  • -Xmx 最大堆大小

  • -Xmn 新生代大小

  • -Xss 线程堆栈大小

非 Stable 参数

各 jvm 实现会有不同

-XX:-UseConcMarkSweepGC 启用 CMS 垃圾回收

JVM 性能诊断工具

  • jps:查看所有 java 进程

  • jstat:对应用程序的资源和性能进行实时的命令行的监控

  • jmap:输出内存中的所有对象

  • jstat:查看堆栈信息

  • jconsole:可视化工具

Java 代码优化

合理谨慎使用多线程

启动线程数= (任务执行时间/(任务执行时间-IO 等待时间))*CPU 核心数

竞态条件与临界区

Java 线程安全

允许被多个线程安全执行的代码称作线程安全的代码

局部变量局部变量存储在线程自己的栈中。也就是说,局部变量永远也不会被多个线程共享。所以, 基础类型的局部变量是线程安全的。局部的对象引用如果在某个方法中创建的对象不会逃逸出该方法,那么它就是线程安全的。对象成员变量对象成员存储在堆上。如果两个线程同时更新同一个对象的同一个成员,那这个代码就不是线程安全的。


发布于: 2020 年 08 月 02 日阅读数: 59
用户头像

qihuajun

关注

还未添加个人签名 2009.05.15 加入

还未添加个人简介

评论 (1 条评论)

发布
用户头像
请添加“极客大学架构师训练营标签”,便于分类~
2020 年 08 月 03 日 14:21
回复
没有更多了
架构师训练营第九周学习总结