JVM运行时内存

      Java虚拟机在执行Java程序的时候会把他所管理的内存划分为若干个不同的数据区域,各个区域有各自的用途,以及创建和销毁的时间。有的区域随着虚拟机进程的启动而存在,有的区域则依赖用户线程的启动和结束而创建和销毁。

Java虚拟机会把运行时的数据区域分为以下几个区域:

   

程序计数器:

       程序计数器是一块很小的内存空间,代表着当前线程执行的字节码的行号指示器,记录着所执行的行号,java虚拟机执行的是由后缀名为.java的文件编译而来的.class文件(字节码文件),字节码解释器根据程序计数器来选取下一条要执行字节码指令,分支、循环,跳转,异常处理、线程恢复等功能。Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,所以为了线程切换后能够恢复到正确的执行位置,每个线程都需要一个独立的程序计数器,各条线程之间计数器互不影响,这样才能保证程序的正确执行,也就是说程序计数器是线程私有的。

Java虚拟机栈:

     java虚拟机栈是用来描述java方法的内存模型,每个方法在执行的同时都会创建一个栈帧,而这个栈帧存储的是方法中的局部变量,操作的数栈,动态链接,方法的出口返回值等信息,当一个方法被调用的时候,就代表着栈帧的入栈,直至方法的结束代表着栈帧的出栈。因为虚拟机栈存储的数据决定了他也是线程私有的,每个线程都拥有一个虚拟机栈记录着方法的内容。我们平时所说的栈就是指的是虚拟机栈,其中存储着基本数据类型和指向堆内存中对象的指针(对象的引用)和returnAddress类型。

本地方法栈:

      这块区域和虚拟机栈执行的操作其实是一致的,但是他们之间的服务对象不一样,虚拟机栈为java方法服务,而本地方法栈为native方法服务,我们在看源码的时候经常了一看到用native关键字修饰的方法,这种方法的实现是用c/c++实现的,我们在平时是看不到他的源码实现的。

Java堆:

     堆内存是这几块内存区域中最大的一块,堆内存存在的目的是存放对象的实例(通过new创建的对象,对象的引用放在虚拟机栈中指向堆中的实例),在虚拟机启动的时候堆内存也就被创建了,这块内存被所有线程共享,在虚拟机运行期间的所有线程创建的对象的实例都被存储在堆内存中。既然堆被线程所共享,那么线程创建的对象不能一直存放在这里,总会有装不下的时候,在一定条件下,java虚拟机会触发垃圾回收机制(GC),来回收这里被看作没有用的对象,虚拟机所管理的垃圾回收器总是会对这块区域进行管理操作。

扫描二维码关注公众号,回复: 2998121 查看本文章

方法区:

    方法区和堆内存一样,是各个线程共享的数据区域,看到这个方法区这个名字很快能想到这个区域存方法信息,事实上方法区存放的数据很多,包括被虚拟机加载的类信息,用final修饰的常量,String对象,用static修饰的静态变量,即时编译器编译后的代码等数据。这个区有时候有人把它称为“永久代”,但是针对不同的虚拟机也许并不存在这个说嘛,这个区域的内存回收目标也是针对常量池的回收和对类型的卸载,不过还是比较难。

运行时常量池:

     准确的说这块区域属于方法区,也就受到了方法区的空间限制,之前所说的String对象,就是字符串常量就是存放在这里,编译期生成各种字面值和符号引用,将在类价在后放入方法区的运行时常量池的。运行时常量池的存储具有动态性,并不是在类编译时才能放入数据,在程序运行期间也可以有新的常量放入。这种在运行期间可以将新的常量放入池中的用的比较多的就是String类的intern()方法。

直接内存:

      这个并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域,但是这部分区域也是经常被使用,而且也可能导致OutOfMemoryError异常出现。这块区域和java中的新的io方式(NIO)有关,NIO是一种基于通道,缓冲区的io方式,他可以使用Native函数库直接分配堆外内存,然后通过存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样能在一些场景中提高性能,因为避免了在Java对和Native堆中来回复制数据。

猜你喜欢

转载自blog.csdn.net/weixin_40792878/article/details/82120575