深入理解java虚拟机笔记第一、二章

 2019-12-22 10:48  阅读(891)
文章分类:JVM

第一章、第二章

1.java技术体系优点

(1)摆脱了硬件平台束缚,“一次编译,到处运行”;

(2)提供了相对安全的内存管理和访问机制;避免了绝大部分的内存泄漏和指针越界问题

(3)实现了热点代码检测和运行时编译及优化,是java应用能随着运行时间的增加而获得更高的性能

(4)第三方类库的支持

2.java技术体系内容

(1)java程序设计语言

(2)各种平台的java虚拟机

(3)class文件格式

(4)java API核心类库

(5)来源商业机构和开源社区的第三方类库

3.Java技术分类

(1)Java Card –运行在一些小内存设备的java小程序

(2)Java ME –运行在移动终端的程序,比如老一代的摩托罗拉手机

(3)Java SE –桌面级应用,比如windows下的应用,核心类库

(4)Java EE –企业级应用,比如java.*是核心类库,javax.*属于扩充,先在也有部分javax.*进入核心类库

4.编译器、解释器、虚拟机

java编译器:将java代码编译成*.class文件–>编译型语言写的程序执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。

解释器:是一种电脑程序,能够把程序语言按特定规则翻译执行–>解释型语言:代码不需要编译,每次执行的时候编译并且运行,因此速度一般较慢;如Python/JavaScript。

java虚拟机:是*.class文件的运行环境,其功能包括将.class文件编译成机器语言运行,包括解释器和执行器。

2019120001329\_1.png

5.几款常见的虚拟机

6.Java虚拟机运行时的内存区域

(1)程序计数器:每个线程私有的小内存空间,是当前线程所执行的字节码文件的行号指示器,当线程进行切换的时候,用来确定每个线程执行代码的位置。如果执行的是Java代码,那么计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native(看注释)方法,那么这个计数器值为空。

(2)Java虚拟机栈:也是线程私有的,生命周期与线程相同。

1>栈帧:每个方法执行的时候都会创建一个栈帧,方法运行时的基础数据结构,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每当一个方法完成的时候,就是一个栈帧从入栈到出栈的过程。

2>局部变量表:局部变量表中存储了编译器可知的各种基本数据类型、对象引用(reference类型,可能是一个指向对象起始地址的引用指针,也可能使指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。局部变量表内存空间在编译期就会完全确定,方法运行期间不会改变变量表的大小。会抛出两种异常。

3>可以通过-Xss参数来设置栈大小;一般报StackOverFlowError异常

(3)本地方法栈:为虚拟机使用到的Native方法服务,也会抛出两种异常,有的虚拟机将本地方法栈和虚拟机栈合二为一。

(4)Java堆:是在虚拟机管理的内存中最大的一部分,所有线程共享,生命周期与虚拟机的生命周期相同,用于存放对象实例,几乎所有的对象实例都在这里分配内存。这也是垃圾收集器管理的主要区域,也称为GC堆,分为新生代和老年代。当堆中没有空间创建对象实例,也不能再扩展的时候,抛出outofmemoryerror。

1>虚拟机可以通过设置-Xms(堆最小值)、-Xmx(堆最大值)来控制堆的大小。

2>OOM异常会进一步提示java heap space

(5)方法区:JDK7及之前版本的方法区(Method Area)和Java堆一样,是各个线程共享的内存区域,用于存储已经被虚拟机加载的类信息、常量、静态常量、即时编译器编译后的代码等数据。会抛出outofmemoryerror。

1>可以通过-XX:PermSize和-XX:MaxPerSize限制方法区大小

2>OOM异常会进一步提示:PermGen space

(6)运行时常量池:存放编译期生成的各种字面量和符号引用。方法区的一部分,受方法区内存限制,会抛出outofmemoryerror。

(7)直接内存:不是虚拟机运行时数据区的一部分,但是可以通过Native函数库来调用,会抛出outofmemoryerror。

1>通过-XX:MaxDirectMemorySize指定大小,如果没指定,默认堆大小

7.Java虚拟机运行时栈常见的两种异常

(1)StackOverFlowError:如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出此异常。

(2)OutOfMemoryError:如果虚拟机栈设置了可以动态扩展,在扩展的时候无法申请到足够的内存,那么会抛出此异常。

8.内存泄漏和内存溢出

(1)内存泄漏(Memory Leak):是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。对象因为某些原因无法回收。

(2)内存溢出(Memory Overflow):程序运行时需要的内存大于能够提供的内存,会抛出此异常。

9.HotSpot虚拟机对象管理

(1)对象创建:虚拟机遇到一条new指令时,先去常量池查看这个指令的参数能否定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过,如果没有,先加载类。类加载时,可以确定所需内存空间,加载后,在堆种分配内存,有指针碰撞和空闲列表两种分配方式,根据采用的垃圾收集器有关。内存分配完成后,将内存空间都初始化为0,这一步保证了对象实例在Java代码种不需要赋初始值就能使用。接下来对对象头进行设置,内容包括哪个类的实例、如何找到这个类的元数据信息、哈希码、对象的GC分代年龄等。执行Init方法(构造函数)。

在分配内存的时候可能碰上线程并发问题,比如A对象加载还没来得及分配内存,B也加载了,两个基本同时使用一个指针分配内存,会出现异常。解决方法有:对分配内存空间进行同步处理;每个线程在堆中预先分配一小块内存做缓冲TLAB,这块缓存用完后使用同步处理。

(2)对象内存布局:对象头、实例数据、对齐补充

1>对象头包括两部分信息:一是储存对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁等;二是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

2>对象的实例数据存储对象的有效信息,按照虚拟机分配策略参数和字段在源代码种定义顺序进行排序。hotspot分配策略为大的分配在前面,父类定义的变量分配在子类前面。

3>对齐补充:对象大小必须是8字节的整数倍,因此通过对齐补充来补全。

(3)对象访问定位

java程序是通过栈上的reference数据来操作堆上的具体对象,这个reference就是一用。如果通过引用去查找对象,有两种方式。

1>通过句柄访问。在堆上划出一块儿内存作为句柄池,管理着引用指向实例数(堆)和类型数据(方法区)的地址。对象在被移动的时候,只要改变句柄中的地址,不需要改变reference。

2>直接指针访问。reference指向对象的实例数据地址,对象实例中有对象类型数据的地址。速度快,节省了一次指针定位的时间。

后续补充中。。

基本的虚拟机了解。

注释:

JDK(Java Development Kit):用于java开发的最小环境,包括API+虚拟机+java程序设计语言。

JRE(Java Runtime Environment):支持java程序运行的最小环境。

JIT编译器(Just-in-time Complier):在运行时,JIT会把翻译过来的机器码保存起来,方便多次调用。参考百科。

Native方法:被native关键字修饰的方法叫做本地方法,本地方法和其它方法不一样,本地方法意味着和平台有关,因此使用了native的程序可移植性都不太高。—>参考地址:https://www.cnblogs.com/HDK2016/p/7226840.html?utm\_source=itdadao&utm\_medium=referral

TLAB(Thread Local Allocation Buffer):java堆种可能划分出多个线程私有的分配缓冲区。

元数据:描述数据的数据,对数据及信息资源的描述性信息。

参考:

1.https://www.cnblogs.com/heyanan/p/6125030.html

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 深入理解java虚拟机笔记第一、二章

相关推荐