JVM个人学习笔记

了解java class文件 HelloWorld.class  被执行 java HelloWorld.class 的过程

执行java HelloWorld.class 被虚拟机 类加载子系统 接收,通过 验证 准备 和解析   并装载到 运行时数据区中 在运行时数据区 

验证:是验证这个编译后的字节码文件的语法是否正确 

准备: 为类的静态变量分配内存,并将其初始化为默认值,final static 修饰的变量(其实就是常量)在编译的时候就已经分配了内存

 

JVM 三大系统

1、类加载子系统

硬盘上编译完成的class文件 需要类加载子系统 加载到 内存中(方法区)

2、执行引擎

真正的代码执行是由 执行引擎通过内存中的数据 去执行的并返回结果

3、JVM运行时数据区(栈和堆组成) 堆 线程共享区域 栈 线程私有区域

 

堆 : 新生代 老年代  举例内存分配600M 默认老年代占400m 新生代200m  (eden占新生代中的8/10,  from 1/10  To 1/10)

新生代: Eden 伊甸园 绝大多数对象默认会存储在 新生代伊甸园区域

eden  伊甸园区对象满的时候会去触发 minorGc 进行可达性分析gc roots 判断对象是否处于游离状态(第一次触发 如果该区域对象还在被使用 就会把这个对象 放在 from 区 并对分代年龄age+1 (分代年龄包含在对象头中)) ,如果处于游离状态则直接回收

from 如果from内存区 也满了 就触发minorGc 判断对象状态 如果存在对象还在使用 就将对象拷贝到 to区 to区 就变成的from区

to 跟from一起配合使用,相当于from的备份分区

老年代:如果from中的对象分代年龄 已经到15了 还没被扔出去 就会进入老年代  如果老年代 没有内存空间可分配的话 会触发fullGC  出现STW (stop world) 暂停当前程序的线程去执行垃圾回收,老年代满了Full GC清理不掉任何对象了,就会出现OOM (outofmemory 内存溢出异常

垃圾回收的对象: 线程执行完,对应的栈空间要被释放掉,栈帧局部变量表所指向的对象就没有了引用,堆对象处于游离状态即要被回收的对象

GC root 根:由本地变量去指向堆中的对象,本地变量就称之为GC root根, 可达性分析算法 就涉及到GC root根,当这个根不存在时,也就代表这 这个引用链为 垃圾对象

 

方法区:用来存储类信息(堆中对象指向类信息)会存在一对多的关系  用来存储常量、静态变量、类元信息  JDK1.8之后用的是直接内存 就是虚拟机的物理内存

类元信息 类的组成信息,比如类名,修饰符。。。

 

虚拟机栈

栈是用来存储局部变量的,一个线程开始执行,即对该线程分配一个栈空间,线程中不同的方法 对应不同的栈帧,即一个栈空间中 对应多个栈帧。栈帧中 又划分为 :局部变量表、操作数栈、动态链接、方法出口

栈 就是数据结构 特点是先进后出 后进先出 first in last out

     虚拟机栈栈帧数据结构:局部变量 、操作数栈、方法出口

操作数栈: 汇编指令 将 常量压入 栈 就是进入的操作数栈 ,临时操作数运算时用到的内存空间

局部变量:32位的存储类型, 会存入基础类型 和引用类型的局部变量对象 利用程序计数器去记录对应指令变量位置 完成赋值

方法出口:存储当前栈帧对应的方法执行完之后 需要回到的方法。举例:main 方法中有子方法执行,子方法执行完需要回到main方法,子方法的方法出口存储的就是main方法程序计数器相关的信息

程序计数器  作用是记录当前线程执行的指令位置或者说 要执行的位置。程序计数器设计的初衷是 多线程情况下 程序挂起后 又被唤醒 可以根据计数器的值的指令位置 继续执行,所以程序计数器也是 线程私有的,即每个线程都拥有一个程序计数器。

本地方法栈:用来存储 由关键字native修饰的方法,执行本地方法时其实是去找方法对应的c语言的执行库,线程私有

 

当栈中new 出来的对象 会存储到堆内存空间,栈中会存储堆内存空间对应的局部变量,也就是对象对应的堆内存地址

 

问题 java 性能调优的目的: 减少Gc的次数,减小触发Full GC后STW 的时间, 在有限的物理内存上做更多并且不会导致影响机器性能的事情

为什么java 需要采用分代回收的策略:  减少stw的次数  减少fullGc的次数  提高程序的吞吐量 jvm调优的目的

 

 

 

おすすめ

転載: blog.csdn.net/u012565281/article/details/105723512
おすすめ