一文了解JAVA虚拟机的重要组成
JVM是JAVA平台的重要组成之一,因涉及知识点太多,故从以下几个方面对JVM进行浅层面的介绍,如果需要深入理解,推荐学习机械工业出版社的《深入理解JAVA虚拟机》。
请尊重作者劳动成果,转载请标明原文链接:
https://www.cnblogs.com/jpcflyer/p/9226988.html
一、JAVA内存结构
Java虚拟机规范中规定的JVM运行时数据区如下图所示:

总体来说,分为线程共享部分(方法区、堆)和线程隔离区(虚拟机栈、本地方法栈和程序计数器)。
1.方法区
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。其中常量存储于运行时常量区中,运行时常量区是区的一部分,用于存储编译期生成的字面量和符号引用。但运行时常量区的内容并不只是在编译期间产生,通过String.intern()也可以实现在运行时向常量区中添加内容。
2.堆
是JVM中最大的一块内存区域,该区域的目的只是用于存储对象实例及数组。该区域也是GC的最主要区域。
3.虚拟机栈
每个线程方法在执行时都会创建一个栈帧,包含局部变量表、返回地址、操作数栈等信息。每个方法的执行与完成就对应的栈帧的入栈与出栈过程 。局部变量表占用空间的大小在编译期就确定了。
4.本地方法栈
与虚拟机栈类似,不过其中执行是本地方法。对于HotSpot虚拟机而言,本地方法栈和虚拟机栈是统一的。
5.程序计数器
是一个小的内存空间,如果线程正在执行的是一个java方法,则此内存区域记录正在执行的虚拟机字节码指令;如果线程正在执行的是native方法,则计算器中的值为空。
二、JAVA垃圾回收机制
JAVA的垃圾回收主要涉及到确定对象是否存活、垃圾收集等算法,其中确定对象回收算法采用的是可达性分析算法,垃圾收集目前各JVM厂商广泛采用的是分代收集算法。这里面主要描述下分代收集算法的过程。

分代收集算法的核心思想是将内存区域按照对象的生存周期阶段进行划分,其中将堆区划分为新生代(young generation)和老年代(old generation)。将非堆区(一般指方法区)划分为持久代(permanent generation)。
1.新生代
新生代又可再分为Eden区和两个Survivor区(两个Survivor区的大小是一样的,便于交换)。新生成的对象都会先在新生代的Eden区进行保存。新生代的特点是每次垃圾回收都会有大量的内存被回收,而且收集比较频繁,所以新生代适合如下的收集算法:
首先,新生成的对象分配到Eden区,如果eden区满了,则将可达性的对象复制到survivor1区,后清空eden区。
然后,如果survivor1区满了,则将eden区与survivor1区的可达性对象复制到survivor2区,后清空eden区和survivor1区,清空完后将survivor2区与survivor1区交换,即保持survivor2是空的。
再次,如果survivor2区也满了,则将eden区、survivor1区、survivor2区的可达性对象复制到老年代中,并清空新生代中。
最后,如果老年代也满了,就触发full gc了。
2.老年代
老年代的内存比新生代大的多,这个区域执行垃圾回收的频度不高。当老年代满时,会触发full gc。
3.持久代
持久代一般指方法区,该区需要回收的有废弃的常量和类。对于常量可用可达性分析的方法进行判断回收,对于类则需要同时满足以下条件才会被回收:
首先,该类的所有实例对象都已被回收;
其次,该类的类加载器也已被回收;
再次,该类的Class方法没有在任何地方被引用,即无法通过在任何地方通过反射访问到该类的方法。
4.什么时候会解决垃圾回收?
综上所述,当eden满时,就会触发scavenge gc,当出现以下情况时会触发full gc:
老年代已满;
持久代已满;
调用System.gc()方法;
三、JAVA类加载过程
JVM类加载过程具体装载、验证、准备、解析、初始化这五个部分。
1.装载
在装载过程中,需要完成以下事情:
1)通过类的全限定名获取类的二进制字节流;
2)将类的二进制字节流转换为方法区的运行时数据结构;
3)生成一个代表此类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
2.验证
验证、解析和初始化又称为是连接阶段,在验证验证主要是确保二进制字节流符合JVM的规范,不会危害计算机的安全。具体验证阶段需要做的事情如下:
1)文件格式验证,验证字节流是否符合Class文件格式规范;
2)元数据验证,对字节码进行语义验证,以保证其描述信息符合JAVA语言规范;
3)字节码验证,通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的;
4)符号引用验证,对常量池中的各种符号引用的信息进行匹配性验证。
3.准备
准备的过程其实是分配内存的过程。在这个阶段有两个容易产生混淆的概念:一是此阶段分配内存的只是类变量(static变量),不包含实例变量,实例变量的内存分配是在对象实例化时随对象一起分配在堆中;二是该阶段分配内存中保存的值只是数据类型的零值,具体值需要在初始化阶段进行赋值。也有特殊情况,就是对于静态常量(final修饰)会在准备阶段将值赋值为真实值。
4.解析
解析阶段就是将常量池内折符号引用转换为直接引用的过程,具体包括类和接口的解析、字段的解析、方法的解析、接口方法和解析。
5.初始化
初始化阶段其实就是执行类构造函数(clinit)的阶段。对于clinit()需要说明以下几点:
1)clinit()中的程序是自动收集类中static变量及static块产生的,执行顺序与代码中的顺序一致。静态语句块中只能访问在其之前声明的static变量,在其之后声明的static变量只能赋值,不能访问。
2)执行clinit()方法前,JVM会自动调用父类的clinit()方法;
3)虚拟机会保证一个类的clinit()在多线程环境中,自动加锁、同步。
四、JVM的类加载器
JVM的类加载是通过类加载器实现的,常用的类加载器包括下面三种:
1.启动类加载器(bootstrap classloader):加载{JDK_HOME}/lib下的类
2.扩展类加载器(extension classloader):加载{JDK_HOME}/lib/ext下的类
3.应用程序类加载器(application classloader):加载classpath指定的类
对于不同类加载器以及他们之间的协作可以参考下面的双亲委派模型。

双亲委派模型的工作过程是:如果一个类加载器收到了类的加载请求,会首先把请求委派给自己的父类,每个层次的类加载器都会如此,因为所有的加载请求最终都会发送到bootstarp加载器中,只有当父加载器确实无法自己完成加载请求时,子加载器才会尝试自己加载。
双亲委派模型使得JAVA类能够按层次进行加载,不会造成混乱。
五、JVM的相关工具
JDK中有很多强大的监控工具,可以直接在命令行运行。这对于在生产环境进行监控是非常有用的。例如SUN JDK中就包含了以下监控和故障处理工具。
jps: jvm process status tool,显示指定系统内所有的hotspot虚拟机进程
jstat: jvm statistics monitoring tool,用于收集hotspot虚拟机各方面的运行数据
jinfo: configuration info for java,显示虚拟机配置信息
jmap: memory map for java,生成虚拟机的内存转储快照(heapdump文件)
jhat: jvm heap dump browser,用于分析heapmap文件,它会建立一个http/html服务器,让用户可以在浏览器上查看分析结果
jstack: stack trace for java ,显示虚拟机的线程快照
先介绍这么多,后面有机会再介绍JVM在并发方面的相关支持。
一文了解JAVA虚拟机的重要组成的更多相关文章
- 一文解析总结Java虚拟机内存区域模型
最近抽空看了一点<深入理解Java虚拟机>,本篇文章主要来总结一下Java虚拟机内存的各个区域,以及这些区域的作用.服务对象以及其中可能产生的问题,作为大家的面试宝典. 首先我们来看一下J ...
- Java虚拟机系列一:一文搞懂 JVM 架构和运行时数据区
前言 之前写博客一直比较随性,主题也很随意,就是想到什么写什么,对什么感兴趣就写什么.虽然写起来无拘无束,自在随意,但也带来了一些问题,每次写完一篇后就要去纠结下一篇到底写什么,看来选择太多也不是好事 ...
- 如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码
程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习< ...
- (1) 深入理解Java虚拟机到底是什么?
好文转载:http://blog.csdn.net/zhangjg_blog/article/details/20380971 什么是Java虚拟机 作为一个Java程序员,我们每天都在写Java ...
- Java虚拟机工作原理详解 (一)
一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘当中.然后你在命令行中输入 javac YourClassNam ...
- Java虚拟机工作原理详解
原文地址:http://blog.csdn.net/bingduanlbd/article/details/8363734 一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了 ...
- [转]JVM内幕:Java虚拟机详解
本文由 ImportNew - 挖坑的张师傅 翻译自 jamesdbloom.欢迎加入翻译小组.转载请见文末要求. 这篇文章解释了Java 虚拟机(JVM)的内部架构.下图显示了遵守Java SE 7 ...
- Java 虚拟机体系结构
众所周知,Java源代码被编译器编译成class文件.而并不是底层操作系统可以直接执行的二进制指令(比如Windows OS的.exe文件).因此,我们需要有一种平台可以解释class文件并运行它.而 ...
- Android(java)学习笔记156:Java虚拟机和Dalvik虚拟机的区别
Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvik虚拟机也第一次进入了人们的视野.它对内存的高效使用,和在低速CPU上表现出的高性能,确实令 ...
随机推荐
- node.js中express的Router路由的使用
express中的Router作用就是为了方便我们更好的根据路由去分模块.避免将所有路由都写在入口文件中. 一.简单的使用Router const express = require('express ...
- Linux 6上使用UDEV绑定共享存储
1.硬盘的查看方式 [root@cl6-11gr2-rac1 ~]# ls -ltr /dev/sd* brw-rw----. 1 root disk 8, 48 8月 16 13:34 /dev/s ...
- Chapter3_操作符_方法调用中的别名问题
接下来展示方法调用中的别名问题,方法调用中的别名问题指的是,将一个对对象的引用传递给某一个方法时,方法操作的是这一个特定的引用而不是这个引用的拷贝. class Person{ float heigh ...
- ABP框架系列之一:(Entity-实体)
Entities are one of the core concepts of DDD (Domain Driven Design). Eric Evans describe it as " ...
- slecte下拉框的多选操作及获取值的 变化
对select增加一个 multiple属性,再获取多选的值的时候,对数据进行遍历,如果单纯的获取select的value值,指挥获取一个值, 遍历方法 可以先获取到select的dom元素到,然后对 ...
- Avro实现RPC
场景:一个客户端,一个服务端(创建两个avro工程).客户端向服务端发送数据,服务端根据算法算出结果,返回给客户端. Http主外,RPC主内.(解决分布式环境下,节点间的数据通信或远程过程调用) 实 ...
- We FALL ASleep At Night, We Do REST Right
We Do Sleep At Night, We Do REST Right 前言 REST 起源 REST 约束 客户端 - 服务端 无状态 缓存 统一接口 分层系统 按需代码 统一接口约束 资源识 ...
- CPP全面总结(涵盖C++11标准)
OOP之类和对象 1. this指针的引入 每个成员函数都有一个额外的隐含的形参,这个参数就是this指针,它指向调用对象的地址.默认情况下,this的类型是指向类类型非常量版本的常量指针.可以表示成 ...
- 札记:翻译-使用Scene和Transition实现【场景切换】动画效果
简述:transitions framework 下面翻译transition为"过渡",强调动画过程的含义,不过更多时候使用transition单词本身. Android 4.4 ...
- Mac OS 中安装 autoconf 和 automake
在Mac上面编译FFmpeg需要安装很多东西,首先是:autoconf 和 automake 请按照以下顺序安装: curl -O http://mirrors.kernel.org/gnu/m4/m ...