JVM解析(一) JVM 运行时内存空间

什么是JVM?

        JVM:Java虚拟机(英语:Java Virtual Machine,缩写:JVM),一种能够执行Java字节码的虚拟机,以堆栈结构机器来实现。最早由Sun微系统所研发并实现第一个实现版本,是Java平台的一部分,能够执行以Java语言写作的软件程序。

        通过维基百科的解释,可以了解到JVM虚拟机,是Java程序运行的基座。Java程序需要在JVM上才可以运行。可以理解为Java程序是在JVM上运行,而不去和底层系统进行交互。JVM的作用是将代码转化为机器能理解的语言,再由机器去执行代码。

JVM的构成有哪些?

    

        JVM主要由运行数据区、执行引擎、本地方法区、本地方法库、类机载器,这五个部分组成。

        执行引擎(execution Engine):将字节码指令解释/编译为对应平台上的本地机器指令。

        本地方法接口(Java Native Interface):调用其他语言写的方法。

        本地方法库:字面意思,可以理解为给本地方法接口提供的操作库。

        类加载器(Class Loader):类加载器内容很多,独立章节讲

        运行时内存空间(Runtime Data Area):JVM关键内容,独立章节讲

运行时内存空间

    什么是运行时内存空间?

        指的是程序运行的时候,JVM的内存组成。不同区域的内存空间负责不同的功能。

    运行时内存空间有哪些部分组成?

           · 程序计数器(Program Counter Register):

           · 线程是没有记忆的,一旦线程被阻塞后再唤醒就不知道自己要做什么,程序计数器用于记录线程执行到哪条指令。

           · 保存当前线程所正在执行的字节码指令的地址

           · 为了在线程切换之后能恢复到正确的执行位置,每个线程都有独立的程序计数器

           · 程序计数器内存区域是虚拟机中唯一没有规定OOM情况的区域

        · 虚拟机栈(VM Stack):

           · 是线程私有的内存,生命周期和线程相同,方法在执行的时候,都会在虚拟机栈中创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈,动态链接、方法出口等信息。

           · 表示方法运行时候,在JVM中的内存模型,最小单位是栈帧。存储存储局部变量表、操作数栈,动态链接、方法出口

               · 局部变量表:存储临时的8个基本数据类型、对象引用地址、returnAddress(保存return后要执行的字节码的指令地址)类型。

                    · 局部变量表在class文件中已经定义好最大大小

                    · 局部变量表的容量以变量槽(Slot)为最小单位,32位的虚拟机中一个Slot可以存放32位以内的数据。

                    · 对于64位长度的数据类型(long double),虚拟机会以高位对齐的方式为其分配两个连续的Slot空间。

                    · Slot是可以重用的,当Slot中的变量超出了作用域,那么下一次分配Slot的时候,会覆盖原来的数据,Slot对对象的引用会影响GC(如果被引用,那么将不会被回收)

                    · 系统不会为局部变量赋予初始值。

               · 操作数栈

                           · 数据操作区域,作为数据临时变更的空间。比如代码有i=66+1,66+1这个操作在操作数栈中计算,然后存入局部变量表中。

                           · 在编译时期已经确定最大大小

               · 动态链接

                           · 存储调用别的方法的地址信息。因为在class文件中,所有的变量和方法引用都是作为符号引用,保存在class文件的常量池中,所以动态链接的作用是将这些符号引用转化为直接引用。比如方法A中要调用方法B,class文件中,写的是B方法名称,在动态链接中存储方法B的名称和地址对应关系。

               · 方法返回地址

                        · 字面意思,有两种返回,正常返回和异常抛出。

               · 本地方法栈(Nactive Method Stack)

                        · 和虚拟机栈的方法类似,只不过服务于Navite方法。

        · Java堆(heap)

            Java虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存。

            · 堆的特点

                · 先进先出

                · 是JVM中占用空间最大的内存,并且运行时动态分配内存大小

                · 所有线程共享的内存

                · GC的主要场所

                · JVM启动的时候创建堆

                · 逻辑上连续的,物理上非连续(内存地址不连续)

            · 堆的构成

                · PermGen Space:永久代。永久保存的区域,用于存放Class和Meta信息,Class在被Load的时候放入该区域,GC不会对PermGen Space进行清理,所以如果有很多的Class被load,那么会跑出OOM异常。JDK1.8之后不存在永久代,改为元空间,也不需要进行内存分配,元数据直接使用系统内存,而不是JVM内存。

                · Young Space:新生代对象,保存刚实例化的对象。当该区被填满时,GC会将对象移到Old Space中。

                · 当中又被分为Eden区、From Survivor区、To Survivor区,存在两个Survivor区域是因为GC要进行复制算法,所以需要两块区域。由于有Survivor区的存在,Eden区不会直接向老年代直接传送对象,减少Full GC的发生,

                · Eden区、From Survivor区、To Survivor区的默认内存比例为8:1:1。

                · Old Space:老年代的对象,在多次Minor GC之后,依旧存在对象会被转移到年老代,老年代的内存空间应该要比年轻代大。与Young Space的内存空间比为1:2。

            · 堆内存分配

                · 最开的内存大小由Xms指定,默认是物理内存的1/64

                · 最大的内存由Xmx指定,默认是物理内存的1/4

                · 堆内存空间小于40%的时候,JVM会增加堆内存大小

                · 堆内存空间大于70%的时候,JVM会减少堆内存的大小

                · 一般将Xms和Xmx设置为同一个值,禁止JVM划分堆内存,优化性能

                · 非堆内存分配(永久代内存分配)

                · 使用-XX:PermSize设置非堆内存的初始值,默认是物理内存的1/64

                · 使用-XX:MaxPermSize设置非堆内存的最大值,默认是物理内存的1/4

            · 垃圾回收机制

                · MinorGC:清理年轻代的内存空间,垃圾回收过程是(复制->清空->互换),采用的算法是复制算法。

                · 过程:当Eden区满的时候,释放在Eden中所有不活跃的对象,活跃的对象放入Survivor区域,并且对象的年龄+1,大对象会直接进入老年区(-XX:PretenureSizeThreshold参数可以设置多大的对象可以直接进入老年区)。如果Survivor区域已经满了,那么会对Survivor进行MinorGC,将年龄达到设置值(默认15)的对象放入老年区。

                · MajorGC:老年代内存不足时,触发老年代GC。采用标记清除法或者标记整理算法的混合实现,该GC不会有MinorGC那么频繁,并且一次MajorGC要比MinorGC时间更长。

                · FullGC:清理整个堆空间

            · 方法区(Method Area)

                · 所有线程共享的,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。

            · 直接内存

                · 在JDK1.4中引入NIO之后,为了视线一种通过native函数直接分配对外内存的,这一切是通过两个概念实现的:channel和buffer。会出现OOM的情况,是受物理机器的内存限制的。

                · 直接内存并不受JVM内存回收管理

 

PS

Q:Java程序是不是只能运行在JVM上?

A:!!!!!---!!!!!从狭义上讲,JVM主要的任务是将class文件翻译为机器码。只要能翻译class文件变为机器码,那就不需要JVM来运行class文件。从广义上讲,能翻译class文件为机器码的东西,可以称之为JVM。

 

Q:JDK、JRE和JVM的区别?

A:JDK是 Java 的开发工具包,提供了 Java 应用程序开发所需的工具和库。JDK 包括 Java 编译器(javac)、Java 虚拟机(JVM)和 Java 库等组件。JDK 可以用于开发 Java 应用程序、Java Servlet 和 Java Server Pages(JSP)等服务器端应用程序,以及 Java 应用程序的桌面版本等。

JRE是 Java 的运行环境,是 Java 应用程序运行的基本环境。JRE 包括 Java 虚拟机(JVM)、Java 标准库和其他组件。JRE 只能用于运行 Java 应用程序,不能用于开发 Java 应用程序。

JVM是 Java 虚拟机,是 Java 应用程序的运行时环境,可以在不同的操作系统上运行 Java 应用程序。JVM 实现了 Java 字节码的解释和执行,并提供了内存管理、垃圾回收等机制。JVM 是跨平台的,可以在不同的硬件平台和操作系统上运行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章