jvm学习笔记(一)
一、java的运行原理
- 开发人员编写java代码(.java文件)
- 编译器将.java文件编译成字节码文件(.class文件)
- 字节码被装入内存,当字节码被装入内存之后,它就会被解释器解释执行或是被即时编译器有选择的转换成机器码执行
二、jvm体系结构
1、类装载(classLoader)子系统
根据给定的全限定名类名来装在.class文件的内容到Runtime Data Area中的method Area(方法区域)。
2、执行引擎(Execution Engine)子系统
执行引擎也叫做解释器(Interpreter),负责解释命令提交给操作系统执行。
3、本地接口(Native Interface)组件
本地接口的作用是融合不同的编程语言为JAVA所用,目前该方法使用的比较少,因为现在的异构领域间的通信很发达,比如socket、webservice等
4、运行数据域(RuntimeDataArea)组件
运行数据区是整个 JVM 的重点。我们所有写的程序都被加载到这里,之后才开始运行
4.1 Java Stack(栈)
栈是在线程创建的时候创建的,它的生命周期是跟随线程的生命周期的,线程结束栈内存就被释放了,所以栈不存在垃圾回收问题。栈主要用于存放引用和基本数据类型(八大基本数据类型)。当一个线程把栈内存用光了之后(一般是递归函数造成的)
就会产生StackOverflowError异常。如果虚拟机栈内存可动态扩展(目前大部分的java虚拟机都可动态扩展),如果扩展时不能申请到足够的内存地址时就会产生oom异常
栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集,当一个方法 A 被调用时就产生了一个栈帧 F1,并被压入到栈中,A 方法又调用了 B 方法,于是产生栈帧 F2 也被压入栈,执行完毕后,先弹出 F2 栈帧,再弹出 F1 栈帧,遵循“先进后出”原则。
栈帧中保存的数据类型:
-
-
- 本地变量(Local Variables),包括输入参数和输出参数以及方法内的变量;
- 栈操作(Operand Stack),记录出栈、入栈的操作;
- 栈帧数据(Frame Data),包括类文件、方法等等。
-
图示在一个栈中有两个栈帧,栈帧 2 是最先被调用的方法,先入栈,然后方法 2 又调用
了方法 1,栈帧 1 处于栈顶的位置,栈帧 2 处于栈底,执行完毕后,依次弹出栈帧 1 和栈帧
2,线程结束,栈释放
4.2 Java heap(堆)
堆内存是跟随jvm的,此部分是所有线程共享的,一个jvm只有一个堆内存,但是堆内存的大小是可以调节的。堆主要用于存贮new出来的对象实例以及实例变量以及数组。当新创建
的对象申请的内存大于当前堆内存中的空闲空间时就会出现oom(Out of Memory)异常.堆是垃圾收集器管理的主要区域,所以有时候也被称为“GC堆”
堆内存组成:
-
- Young Generation Space 新生区
新生区 (Young Generation Space) |
伊甸区(Eden Sapce) |
所有的类都是在该区域内new出来的,当该区域内空间用完而jvm又需要创建新的对象时,jvm对该区进行垃圾回收,将不再被其他对象引用的对象销毁,并且将剩余的对象移到幸存0区。加入0区空间也满了,jvm就会堆0区进行垃圾回收。并将对象移到1区,如果1区也满了同样会对1区进行来及回收,并将对象移到养老区 |
幸存0区(Survivor 0 Space) |
主要保存从伊甸区筛选出来的对象 |
|
幸存1区(Survivor 1 Space) |
主要保存从伊甸区筛选出来的对象 |
-
-
- Tenure generation space 养老区
-
养老区用于保存从新生区筛选出来的 JAVA 对象,一般池对象都在这个区域活跃。
-
-
- Permanent Space 永久存储区
-
永久存储区是一个常驻内存区域,用于存放 JDK 自身所携带的 Class,Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不
会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。此外,该区域还会保存一些常量,这些常量可以是编译期已克制的常量,也可以是运行期生成的常量(例如
String.intern()方法)
4.3 Method Area(方法区)
方法区是被所有线程共享,用于存贮已被虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码等数据。此部分还包含运行时常量池(Runtime Constant Pool),运行时常量池
保存的时编译器生成的各种变量和符号引用。
4.4 PC Register(程序计数器)
程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行
的字节码指令。如果线程执行的时一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是native方法,那么这个计数器的值则为空(Undefined)。此内存区域是唯一一个在java虚拟机规范中没有规定任何oom(Out Of Memory)情况的区域
4.5 Native Method Stack(本地方法栈)
本地方法栈是为虚拟机使用到的native方法服务,它的实现的语言、方法与结构并没有强制性的规定。这个区域会抛出 StackOverflowError 和 OutOfMemoryError 异常。