JDK: Java语言的软件开发工具包
JRE:包含Java核心库和支持文件
JVM:JDK和JRE的重要组成部分,Java运行平台
JVM:Java运行平台
JVM(Java Virtual Machine):Java 虚拟机,用来执行 class 文件、保证 Java 语言跨平台
Java 虚拟机可以看做是一台虚拟的计算机,和真实的计算机一样,它有自己的指令集 以及各种运行时内存
JVM 就是一个字节码翻译器,它将字节码文件翻译成各个系统对应的机器码,确保字节码文件能在各个系统上正确的运行
在运行程序时首次运行类时进行加载->连接->初始化
作用:加载类文件
①加载
②连接
③初始化
作用:存储数据
运行时数据区包含:
① 方法区(Method Area):存储所有类,相关信息,属性,常量池(字符串常量),静态变量,常量等
②堆区(Heap Area):所有的对象、变量、数组都存在在该区域
③虚拟机栈(Stack Area):线程私有的,每个线程会创建单独的运行时栈,局部变量都存在于栈内存中
④程序计数器(PC Registers):线程安全的,每个线程都有单独的计数器,主要用于保存当前要执行的指令号,一旦指令执行,计数器将更新到下一条指令号
⑤本地方法栈(Native Method stack):线程安全的,每个线程单独创建自己的本地方法区,主要用于保存本地方法信息
① 解释器:读取字节码,读一行,解释一行
② 即时编译器:由于一段代码被多次调用,都需要解释执行,即使编译器可以将这样的字节码编译为本地代码,用于多次调用时提高系统星能
③垃圾回收器:收集并删除未引用对象,可以调用System.gc()
来触发垃圾回收器进行垃圾回收,垃圾回收器只回收new关键字创建的对象,使用finalize方法清理其他对象。
④本地方法接口:与本地方法库交互,提供执行引擎所需要的本地库
⑤ 本地方法库:(本地方法接口实现类),执行引擎所需要方法库集合
作用:保存当前要执行的指令的地址(指令号),一旦执行指令,计数器将更新到下一条指令的地址(指令号)
每个线程都有单独的计数器,它属于线程私有的,用于存储当前线程要执行的代码指令地址 (行号)
程序计数器是线程安全的(运行数据区中唯一一个不会发生内存泄漏的区域)
JVM 指令通过 javap –v test.class
反解析获得(javap反解析工具,它的作用就是
根据 class 字节码文件,反解析出当前类对应的 code 区(汇编指令)、本地变量表、异
常表和代码行偏移量映射表、常量池等等信息。)
执行过程:
计数器读入要执行的 JVM 指令号
CPU 获取计数器中的指令号
CPU 根据从计数器中获取的指令号执行相对应的指令
计数器更新要执行的下一个 JVM 指令号
Java方法执行的内存模型
用来存储局部变量
局部变量大小在编译期间就可以确定其大小,程序执行期间不会局部变量表大小是不会改变的
存储当前正在计算的数据
当一个方法开始执行时操作数栈创建并且为空
随着方法的执行,会从局部变量表或对象实例的字段中复制所需要的数据到操作数栈,再将计算的进行将栈的元素出栈到局部变量表或返回给调用者
指向运行时常量池的引用
方法返回地址是方法调用的返回,包含正常返回(有返回值)和异常返回(无返回值),不同的返回值类型有不同的指令
无论方法采用何种方式退出,在方法退出后都需要返回到方法调用的位置,程序才能继 续执行,方法返回时可能需要在当前栈帧中保存一些信息,用来帮助它恢复上层方法的执行 状态
当栈内存不足时就会发生栈内存溢出错误,可以通过设置栈的大小来改变栈所占空间的 大小
栈帧多过导致栈内存溢出 (方法递归调用)
栈帧过大导致栈内存溢出(方法中局部变量占用空间过大)
栈溢出错误:java.lang.StackOverflowError
栈内存大小默认值:
Linux:1024KB
,Mac:1024KB
Windows:依赖虚拟机大小(1024kB)
本地方法栈的功能和特点类似于虚拟机栈,也是线程私有的,不同的是虚拟机栈服务的 是 Java 方法,而本地方法栈服务的是 Native 方法
native
修饰的方法为本地方法,没有方法体;JVM内存空间所占区域最大的一块
堆内存溢出是Java非常常见的故障
堆内存分区管理是便于垃圾回收
在进行堆内存垃圾回收时,堆内存中所有对象都不能使用,程序会等同于暂停,暂停后进行回收显然不行。
堆内存回收,是通过将不再存活的对象进行标记,来进行垃圾回收;
回收后,会产生内存碎片,会对内存进行整理空闲
当from区满后,再次创建对象,此时对from区进行垃圾回收,存活下来的对象存储到ToSPace
ToSpace:经from区再次存活下来的对象存储到该区,并标记为2(意为躲过两次垃圾回收),此时生成区存活下来的对象也存储在该区,标记为1
to区满后,对to区进行垃圾回收,再次存活下来的对象存储在from区并进行标记
依次,如上过程,当一个对象标记为15(躲过15次垃圾回收),就会转到 老年代
Minor GC : 清理年轻代
Major GC : 清理老年代
Full GC : 清理整个堆空间,包括年轻代和永久代
所有 GC 都会停止应用所有线程。
堆的所占用的内存大小是可以扩展的,使用“-Xms”和“-Xmx”来控制堆的最小和最大内存
会发生内存泄漏: 是指程序中已动态分配的堆内存由于某种原因程序(僵尸对象)未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果,内存泄漏最终会导致内存溢出。
堆内存中会不断生成新对象,不断的被使用,如果不使用垃圾回收,就可能发生内存溢出
内存溢出:指程序在申请内存时,没有足够的内存空间供其使用。
申请5kb内存但内存只剩2kb
JVM 堆内存常用参数
参数 | 描述 |
---|---|
-Xms | 堆内存初始大小,单位 m、g |
-Xmx(MaxHeapSize) | 堆内存最大允许大小,一般不要大于物理内存的 80% |
-XX:PermSize | 非堆内存初始大小,一般应用设置初始化 200m,最大 1024m 就够了 |
-XX:MaxPermSize | 非堆内存最大允许大小 |
-XX:NewSize(-Xns) | 年轻代内存初始大小 |
-XX:MaxNewSize(-Xmn) | 年轻代内存最大允许大小,也可以缩写 |
-XX:SurvivorRatio=8 | 年轻代中 Eden 区与 Survivor 区的容量比例值,默认为 8,即 8:1 |
-Xss | 堆栈内存大小 |
System.gc()
:清理对象
finalize()
:对象清理前被回收,主要用于清理对象所占用的资源
可以通过-XX:+ PrintGCDetails
JVM设置打印垃圾清理日志
堆内存溢出错误: java.lang.OutOfMemoryError: Java heap space
一般用于存储,类相关信息,常量,静态变量,常量池(字符串常量), 即时编译器编译后的代码缓存,属性,方法信息等。。。
类相关信息(类class、接口interface、枚举enum、注解annotation):
① 这个类型的完整有效名称(全名=包名.类名)
② 这个类型直接父类的完整有效名(对于interface或是java.lang.0bject,都没有父类)
③这个类型的修饰符(public,abstract,final的某个子集)
④这个类型直接接的一个有序列表
方法信息
① 方法名称
② 方法的返回类型(或void)
③方法参数的数量和类型(按顺序)
④ 方法的修饰符(public,private,protected,static,final,synchronized, native,abstract的一个子集)
⑤ 方法的字节码(bytecodes)、操作数栈、局部变量表及大小(abstract和native方法除外)
⑥ 异常表( abstract和lnative方法除外)每个异常处理的开始位置、结束位置、代码处理在程序计数器中的偏移地址、被捕获的异常类的常量池索引