JVM之运行时内存 -- 01


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

Java运行时内存

 Java虚拟机会把运行时的数据区域分为以下几个区域:
在这里插入图片描述

1.1 程序计数器
  • 程序计数器是一块较小的内存空间,是当前线程所执行的字节码的行号指示器
  • 程序计算器处于线程独占区
  • 如果线程执行的是java方法,记录的是正在执行的虚拟机字节码指令的地址,如果是native方法,这个计数器值为undefined
1.2 Java虚拟机栈

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

  • 局部变量表:表示当前栈帧(方法)中的变量,默认第0个是this(非静态方法)
  • 操作数栈:也是一个栈,用来操作当前栈帧中的数据运算。
  • 动态链接:表示动态决定引用的地址,比如我们经常用的多态
  • 出口:表示方法的出口地址

栈 溢 出:StackOverflowError,OutOfMemory
如图:
在这里插入图片描述

1.3 本地方法栈

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

1.4 Java堆

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

1.5 方法区

  方法区和堆内存一样,是各个线程共享的数据区域,看到这个方法区这个名字很快能想到这个区域存方法信息,事实上方法区存放的数据很多,包括被虚拟机加载的类信息,用final修饰的常量,String对象,用static修饰的静态变量,即时编译器编译后的代码等数据。虽然JVM规范将方法区描述为堆的一个逻辑部分,但它却还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。

这个区有时候有人把它称为“永久代”,但是针对不同的虚拟机也许并不存在这个说嘛,这个区域的内存回收目标也是针对常量池的回收和对类型的卸载,不过还是比较难。方法区相当于一个概念,“永久代”和“元空间”是方法区的不同实现。

  永久存储区是一个常驻内存区域,用于存放JDK自身所携带的 Class,Interface的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。
  如果出现java.lang.OutOfMemoryError: PermGen space,说明是Java虚拟机对永久代Perm内存设置不够。一般出现这种情况,都是程序启动需要加载大量的第三方jar包。例如:在一个Tomcat下部署了太多的应用。或者大量动态反射生成的类不断被加载,最终导致Perm区被占满。

  • Jdk1.6及之前: 有永久代, 常量池1.6在方法区
  • Jdk1.7: 有永久代,但已经逐步“去永久代”,常量池1.7在堆
  • Jdk1.8及之后: 无永久代,常量池1.8在元空间
1.6 运行时常量池

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

1.7 直接内存

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值