JVM入门级总结
(个人对黑马程序员JVM完整教程总结,原视频地址https://www.bilibili.com/video/BV1yE411Z7AP)
JVM定义:
Java Virtual Machine - java 程序的运行环境 (java 二进制字节码的运行环境)
好处:
1、编写一次后可以导出运行,对外提供了一致的运行环境
屏蔽了 字节码 和 底层操作系统 的差异 jvm执行二进制字节码来实现代码
2、自动内存的管理机制,提供了垃圾回收的功能
3、能够数组下标越界检查
4、实现多态
JVM内存结构:
一、程序计数器(寄存器) Program Counter Register
java源代码 --> jvm指令 --> 二进制字节码 --> 解释器 --> 机器码 --> CPU
程序计数器作用:
记住下一条jvm指令的执行地址(通过寄存器实现)
程序计数器特点:
1、是线程私有的(属于该线程)
2、不会存在内存溢出
二、虚拟机栈
虚拟机栈定义:
每个线程运行时所需要的内存,称为虚拟机栈
每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
每个线程只能有一个 活动栈帧,对应着当前正在执行的那个方法
栈:线程运行时需要的内存空间
栈帧:每个方法运行时需要的内存(其中有 参数、局部变量、返回地址等)
栈帧 和 栈:
每当调用方法时,
为第一个栈帧开辟空间,将其压入栈内
该方法执行完后,释放内存空间,栈帧出栈
若 方法一 中调用了 方法二,方法二 中调用了 方法三
则 栈帧1,栈帧2,栈帧3 会依次进入栈,再按 先入后出 释放内存并出栈
问题辨析:
1、垃圾回收是否涉及栈内存
不涉及,每当方法结束时,内存会被自动弹出栈,会被自动回收掉
垃圾回收只回收堆内存中的垃圾
2、栈内存越大越好?
不是,因为物理内存是固定的,栈内存如果越大,线程数量就会越少
3、方法内的局部变量(非静态)是否线程安全?
一个线程产生一个栈帧,各调各的,所以线程安全
(还需要判断该变量是否逃离该方法的作用范围,如果没有逃离,则安全,反之不一定)
栈内存溢出:
java.lang.StackOverflowError
原因:
1、栈帧过多(例如 递归)
2、栈帧过大
三、本地方法栈
调用本地方法时的栈(一些带有关键字 native 的c c++ 的方法)
四、堆
通过 new 关键字 创建的对象都会使用堆内存
特点:
1、它是线程共享的,堆中的对象都需要考虑线程安全的问题
2、有垃圾回收机制
堆内存溢出:
java.lang.OutOfMemoryError
虽然有垃圾回收机制,但是如果堆中的对象都有在被使用则不需要回收,过大过多是就会溢出
五、方法区
方法区的定义:
jdk1.8
方法区是所有java虚拟机线程共享的区域
它存储了跟类的结构相关信息,比如 类的成员变量,方法数据,成员方法,构造器方法 等等
方法区逻辑上是堆的一部分但在不同的jvm厂商实现起来不一定是
组成
方法区内存溢出:
1.8之前导致永久代内存溢出
1.8之后导致元空间内存溢出
运行时常量池:
二进制字节码(类基本信息,常量池,类方法定义,包含了虚拟机指令)
常量池:
就是一张表,虚拟机指令 根据这张常量表去找到要执行的类名、方法名、参数类型、字面量等信息
运行时常量池:
常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址(内存中的地址)。