首页 > 编程语言 > 详细

java运行时数据区和常量池概念

时间:2019-05-07 16:33:50      阅读:188      评论:0      收藏:0      [点我收藏+]

在了解运行时数据区之前,可以先学习下常量池的概念。

1、字符串常量池

  在HotSpot中通过StringTable类实现功能,StringTable是一个hash表(读过hashmap源码差不多),默认长度大小1009,被所有类共享。字符串常量由字符组成,保存在StringTable上面。

  在jdk1.6当中,StringTable的长度是固定1009,如果存放在StringTable中的字符串很多,造成hash冲突的几率很大,链表过长,当通过String.intern()查找String Pool时,性能就会降低。

  在jdk1.7当中,StringTable的长度可以通过-XX:StringTableSize设置

存放的内容

  String.intern()主要是为了复用字符串常量,节省内存空间

  在jdk1.6及以前的版本,存放的都是字符串常量

  在jdk1.7之后,String.intern()发生变化,返回对象的引用,因此除了字符串常量,也可以存放堆中字符串常量的引用

在jdk1.7之后,字符串常量池从方法区转移到堆中

2、class常量池

  首先java代码通过javac编译成class文件,class文件中保存着类的相关信息(版本,类、字段、方法、接口等信息),除此之外,还有Class常量池,用来存放编译器产生的各种字面量(Literal)和符号引用(Symbolic References),每个class文件都有一个class常量池。

  字面量:1.String  2.基本数据类型  3.声明final的常量

  符号引用:1.类和方法的全限定名(类似于com.cfets.**.**这种)  2.字段的名称和描述符  3.方法的名称和描述符

3、运行时常量池

  就是class常量池被加载到方法区之后的版本,区别就是:字面量可以通过String.intern()动态添加,符号引用解析为直接引用(类加载的解析阶段

  当类加载到内存之中,jvm会把class常量池的内存存放到运行时常量池,所以,运行时常量池也是每个class都有的。

  符号引用:上述有说明。以一组符号来描述所引用的目标,只要能定位到目标,无论是任何形式的字面量,和jvm实现的内存布局无关。

  直接引用:直接指向目标的指针、相对偏移量或者间接定位到目标的句柄,句柄和指针对应对象的访问定位方式,和jvm实现的内存布局有关。
  

java运行时数据区:也可以称为java内存区域,和java内存模型不是一回事,不要弄混

方法区:线程共享

  jdk1.8之前HotSpot通过永久带实现方法区,为了把GC可以像堆一样管理内存,能够复用代码,1.8移除永久带,通过本地内存实现方法区,其他虚拟机没有永久带的概念,因为更容易出现内存溢出

  主要存放类信息、常量、静态变量、即时编译后的代码等

  垃圾回收主要是针对常量池回收和类型的卸载,这块区域的回收很难,尤其是类型卸载,可以选择不进行垃圾回收,但是回收很有必要的


虚拟机栈:线程私有,生命周期和线程相同

  每执行一个方法都会创建一个栈帧,从执行到结束,对应着栈帧在虚拟机栈的入栈到出栈过程

  栈帧:保存着局部变量表、操作数栈、方法出入口等

  局部变量表:用来保存方法参数和返回值,也就是基本数据类型、对象的引用、returnAddress类型(指向一个字节码指令的地址)

  double和long占用两个局部变量空间(variable slot),其余占用1个,slot空间大小在编译期间就确定,方法运行期间无法改变

  可能出现Stack OverflowError、OutOfMemoryError错误


本地方法栈:线程私有

  和虚拟机栈相似,一个为Java方法服务,一个为了本地方法服务,本地方法栈中方法实现的语言、方式等没有规定,由具体的虚拟机确定,在HotSpot中只有栈,没有虚拟机栈和本地方法栈的区别。

  可能出现Stack OverflowError、OutOfMemoryError错误


:线程共享

  这是虚拟机内存最大的一块区域,也是GC的主要区域,几乎所有的对象和数组都保存在这里

  内存回收的角度分为:

    新生代:Eden Space、From Survivor、To Survivor

    老年代:

      1、主要用来保存大对象(可以通过-XX:PretenureSizeThreshold 设置大对象的阀值)

      2、或者从新生代经过15次 minor GC存活下来的对象(-XX:MaxTenuringThreshold)        

      3、第二条不是绝对的,VM动态判断,如果Survivor空间中相同年龄所有对象大小的综合大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold要求的年龄

    默认Eden Space:From Survivor:To Survivor=8:1:1,可以通过-XX:SurvivorRatio调节,一般不需要

    新生代和老年代默认是1:2,可以通过-XX:NewRatio调节


程序计数器:线程私有

 

  是一块很小的内存区域,记录着当前虚拟机字节码指令的地址(对于JNI,值为undefined),字节码解释器通过改变计数器的值来选择下一条执行的字节码,分支、循环、跳转、异常处理、线程恢复等功能都要依靠计数器。
  线程上下文切换的时候,当进行线程恢复的时候,需要每个线程拥有私有的程序计数器才能恢复到正确的执行位置
  唯一一个没有规定OOM的区域

 

直接内存:(个人理解不深,对这个没啥概念) 

  不属于Java运行时内存,有可能出现OOM,jdk1.4出现了NIO,它可以通过Native函数库分配堆外内存,通过Java堆中的DirectByteBuffer对象作为引用进行操作,在某些场景明显提高性能,以为避免了Java堆和Native堆来回复制数据。
  直接内存的分配不受Java堆大小限制,而是收到本机总内存的限制。

本地内存:就是JMM的概念了,后面写JMM的时候再讲

java运行时数据区和常量池概念

原文:https://www.cnblogs.com/huigelaile/p/diamondshine.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!