jvm内存模型介绍

什么是JVM?

所谓JVM就是JAVA虚拟机(Java Virtual Machine)。这也正是Java牛逼的地方所在,众所周知,Java的特点就是“一次编译,到处运行”。这就是JVM做到的,JVM就是一台虚拟的计算机,把具体的机器指令屏蔽起来,用自己独有的一套东西。开发者编写的程序经过编译器生成Java虚拟机上运行的目标代码(字节码),就可以无视平台,带来的弊端也显而易见,Java虚拟机在执行字节码时,也需要把字节码解释成具体平台上的机器指令执行。举个例子:我们吃饭,西餐用刀叉,吃中餐用筷子,吃汉堡直接用手,我们需要针对吃不同的东西选择不同的方式,这就相当于我写Windows程序,或者写Mac程序,亦或者写Android程序,写不同的程序我要用不同的语言和编辑器。JVM是什么呢?就相当于我吃饭工具的一个盒子,里面有各种各样的工具,我不需要考虑我吃的是什么,吃就完了,反正有盒子替我考虑。

JRE/JDK/JVM是什么关系?

JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台。所有的Java 程序都要在JRE下才能运行。普通用户只需要运行已开发好的java程序,安装JRE即可。 
JDK(Java Development Kit)是程序开发者用来来编译、调试java程序用的开发工具包。JDK的工具也是Java程序,也需要JRE才能运行。为了保持JDK的独立性和完整性,在JDK的安装过程中,JRE也是 安装的一部分。所以,在JDK的安装目录下有一个名为jre的目录,用于存放JRE文件。 
JVM(JavaVirtualMachine,Java虚拟机)是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。

JVM原理

JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行java的字节码程序。 
JVM 内存模型图 
这里写图片描述 
java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。

JVM内存

这里写图片描述
JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的),Native Method Stack ( 本地方法栈 ),其中Method Area 和 Heap 是线程共享的 ,VM Stack,Native Method Stack 和Program Counter Register 是非线程共享。为什么分为 线程共享和非线程共享的呢?请继续往下看。

首先我们熟悉一下一个一般性的 Java 程序的工作过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢?

概括地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么我把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说知发生在Heap上)的原因。

这里写图片描述 
堆(Heap)是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。 
这里写图片描述

  1. 堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的
  2. Sun Hotspot JVM为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间TLAB(Thread Local 
    Allocation 
    Buffer),其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程的对象分配内存时会尽量的在TLAB上分配,在这种情况下JVM中分配对象内存的性能和C基本是一样高效的,但如果对象过大的话则仍然是直接使用堆空间分配
  3. TLAB仅作用于新生代的Eden Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。
  4. 所有新创建的Object 都将会存储在新生代Yong Generation中。如果Young 
    Generation的数据在一次或多次GC后存活下来,那么将被转移到OldGeneration。新的Object总是创建在Eden Space。 
    堆我并不是很理解,大佬们帮助理解一下,十分感谢。

方法区域(Method Area)存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息

本地方法堆栈(Native Method Stacks)存放每个native方法的调用状态。

程序计数器(Program Counter Register)是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行。

虚拟机栈(VM Stack)描述的是Java方法执行的内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息。

JVM垃圾回收

GC (Garbage Collection)的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停

  1. 对新生代的对象的收集称为minor GC;
  2. 对旧生代的对象的收集称为Full GC;
  3. 程序中主动调用System.gc()强制执行的GC为Full GC。
  4. 不同的对象引用类型, GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型: 
    (1)强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收) 
    (2)软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC) 
    (3)弱引用:在GC时一定会被GC回收 
    (4)虚引用:由于虚引用只是用来得知对象是否被GC

猜你喜欢

转载自blog.csdn.net/JAVA_55555/article/details/84112351