威哥有2个月没有写博客了,动手写写JVM内存模型,也当做是自己成长的笔记。
JVM:Java Virtual Machine,即Java虚拟机,用于运行Java程序编译后的字节码文件。java运行环境的一部分,是一个虚构出来的计算机,它是通过在实际的计算机上仿真模拟各种计算机功能来实现的。即一次编写,到处运行。
当我们写java代码时,实际上是写.java文件,之后通过编译器编译威.class文件,然后通过ClassLoader(类加载器)把类信息加载到JVM中。最后JVM再调用操作系统,这样就实行了跨平台。
.java文件如下:
.java文件可以通过IDEA编译威.class文件或者提供javac编译。
在介绍JVM内存模型前,我们先理一下JVM的种类,以及Java的堆和栈的概念。
JVM:Java虚拟机,主要有3种,如下。
1、Sun公司的HotSpot 是目前使用范围最广的Java虚拟机。
2、BEA公司的JRockit(原来的 Bea JRockit)电脑软件,系列产品是一个全面的Java运行时解决方案组合。
3、IBM公司的J9 VM 是一个高性能的企业级 Java 虚拟机。
Java 把内存划分成两种:
1、一种是栈内存;
2、另一种是堆内存。
栈:
栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, boolean, char)和对象句柄(引用类型变量)。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。
威哥这里解释下什么是:引用类型变量?
如:ShopComment model = new ShopComment();
model就是引用类型变量,该变量的引用指向的堆中new出来的对象实体。
优点:存取速度比堆要快,仅次于寄存器,栈数据可以共享。
缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
堆:
用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。
理解了堆和栈,我们接着来看JVM内存模型,下面是威哥画好的一张JVM内存模型图:
1、方法区(Method Area):
方法区主要是放类似类定义、常量、编译后的代码、静态变量等。在JDK1.7中,HotSpot VM的实现就是将其放在永久代中,这样的好处就是可以直接使用堆中的GC算法来进行管理,但坏处就是经常会出现内存溢出,即PermGen Space异常,所以在JDK1.8中,HotSpot VM取消了永久代,用元空间取而代之,元空间直接使用本地内存,理论上电脑有多少内存它就可以使用多少内存,所以不会再出现PermGen Space异常。
威哥这里稍微解释下PermGen Space:
PermGen space的全称是Permanent Generation space,是指内存的永久保存bai区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被du放到PermGen space中,它和存放类实例(Instance)的Heap区域不zhi同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误。
2、堆(Heap):
几乎所有对象、数组等都是在此分配内存的,在JVM内存中占的比例也是极大的,也是GC垃圾回收的主要阵地,平时我们说的什么新生代、老年代、永久代也是指的这片区域。
3、虚拟机栈(Java Stack):
当JVM在执行方法时,会在此区域中创建一个栈帧来存放方法的各种信息,比如返回值,局部变量表和各种对象引用等,方法开始执行前就先创建栈帧入栈,执行完后就出栈。
4、本地方法栈(Native Method Stack):
和虚拟机栈类似,不过区别是专门提供给Native方法用的。
Native方法:一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C,或者C++。
5、程序计数器(Program Counter Register):
占用很小的一片区域,我们知道JVM执行代码是一行一行执行字节码,所以需要一个计数器来记录当前执行的行数。
6、执行引擎:
关于此点,威哥也没有太专业的学术名称解决,大概的意思就是,JVM 解释执行Java字节码指令,即调用字节码指向得本地机器码。
7、本地接口库:
Java本地接口(JNI)是为java编写本地方法和jvm嵌入本地应用程序的标准的应用程序接口。首要的目标是在给定的平台上通过所有的jvm来实现兼容的二进制编码本地方法库。本地接口的作用是融合不同的编程语言为Java所用,它最初的初衷是融合C/C++程序。
8、本地方法库:
此处就不做过多解释,大家都是程序猿,当然知道本地接口库的接口调用的是真实的实行子类,那就是这个了。