jvm学习笔记1:JVM内存数据区域介绍


1:程序计数器
         字节码的行号指示器,字节码解释器通过改变计数器的值来选取下一条需要执行的字节码指令,计数器是线程私有内存,多线程情况下。当虚拟机将一条线程切换到另一条线程时通过该线程内部的计数器来恢复该线程原来的执行位置
         如果线程执行的是一个java方法,则计数器值是正在执行的字节码指令地址,如果正在执行的是个natvie方法,则计数器值为null
         还有该内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域,也就是说该内存区域在任何情况下都不会出现O utOfMemoryError
2:虚拟机栈,本地方法栈
          虚拟机栈也是线程私有的,它的生命周期跟线程相同
         虚拟机栈是java方法的内存模型 : 每个方法被执行的时候会创建一个栈帧(stack frame),用于存储局部变量表(1),操作栈,动态链接,方法出口,每个方法被调用直至执行完成的过程对应着一个栈帧在虚拟机栈中入栈出栈的过程
         本地方法栈跟虚拟机栈基本类似,区别是本地方法栈是为虚拟机使用的natvie方法服务,而虚拟机栈为 虚拟机 使用的java方法服务
         可以通过-Xss来调节栈的内存容量
3:java堆
         java堆内存被所有线程共享,所有对象跟数组都在这里分配内存,这里也是垃圾搜集器管理的主要区域,
          从内存回收角度来看:由于收集器都采用分代收集算法回收内存垃圾,所以java堆还可以细分为:新生代,老年代;再细致一点的有Eden空间,from survivor空间,to survivor空间等。
         从内存分配角度来看:线程共享的java堆可能划分出多个线程私有的内存缓冲区(Thread local allocation buffer,TLAB)
         可以通过配置启动参数 -Xms(最小堆内存) -Xmx(最大堆内存)来控制堆内存容量是固定的还是可扩展的,如果java堆中没有足够的内存分配对象实例,并且也无法扩展时,将会抛出OutOfMomeryError

4:方法区
         方法区跟java堆一样被所有线程共享,它用于存储已被虚拟机加载的类信息,常量,静态变量以及即时编译器编译后的代码等数据
         方法区也被成为永久代,因为垃圾搜集行为在这个区域很少出现,但并不意味着数据进入了方法区就如永久代的名字一样永久存在了,这个区域还是会被内存回收的,主要目标针对是常量池的回收跟类型的卸载
         可以通过配置 启动参数-XX:permSize(最小 持久代 内存)-XX:maxPermSiz(最大持久代内存)来控制方法区容量是固定的还是可扩展的。当方法区无法满足内存分配的需求时, 将会抛出OutOfMomeryError
5:运行常量池
         运行常量池是方法区的一部分,class文件除了有类的版本,字段,接口,方法等描述外还有一项常量池,用于存储编译期生成的各种字面量跟符号引用。常量池具有动态性,可以在运行期将新的常量放入常量池中。

6:对象内存布局
   对象布局 :在HotSpot虚拟机中,对象在内存中的存储布局分为3块,对象头,实例数据,对齐填充,
            对象头分为两部分,第一部用于保存对象运行时数据,例如hash码 ,GC分代年龄,锁状态标识,线程持有的锁。第二部分存储对象类型指针,该指针指向对象的元数据,虚拟机通过该指针确定对象属于哪个类的实例。 如果对象是数组那么在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机在对象的元数据中可以确定对象的大小,但是在数组中通过元数据却无法确定数组的大小
实例数据,保存对象所有字段的数据,包括从父类中继承的还是从子类中定义的
对齐填充,该部分不是必然存在的,没什么含义。仅仅是起到占位符的作用,因为HotSpot VM的自动内存管理系统要求对象的大小必须是8字节的整数倍,而对象头部分正好是8字节的倍数,所以当对象实例数据部分不是8字节的倍数时,就需要通过对齐填充来补全,已达自动内存管理系统要求的对象大小为8字节的整数倍的条件。

  对象访问定位:
         object obj = new object() ,
          假如该语句出现在方法体中,那么obj将会在java栈的本地变量表中作为一个reference类型出现,new object 将对在java堆中形成一块存储了object类型所有实例数据值(对象所有字段的数据)的结构内存,另外在java堆中还必须包含能查到该对象类型数据(对象类型,实现接口,父类,方法等)的地址信息,这些类型数据存储在方法区中
         因为reference类型只是一个指向对象的引用,并没有规定这个引用通过那种方式去定位以及访问到java堆中对象的具体位置,因此有不同方式去实现对象的访问,主流的方式方式有两种:句柄访问跟 直接 指针
         句柄访问方式:java堆会划出一份内存作为句柄池,reference存储的是句柄池中 对象 句柄的地址,而句柄包含着对象实例数据与类型数据各自的具体地址
         
         直接指针 : reference直接保存对象在java堆中的地址
         
         这两种访问方式都各有优势,句柄方式最大的好处是reference类型中储存着稳定的句柄地址,当对象被移动时,只需要改变句柄中实例数据的地址就行了,reference本身不需要改变,
         直接指针访问方式最大的好处就是速度更快,它节省了一次定位的时间开销,由于对象访问非常频繁,所以这种方式的性能会更好,java默认的HotSpot使用的就是这种方式。
(1) 局部变量表:局部变量表的大小在编译期间完成分配,它存储着基本数据类型(int,char,short,long,float,double,boolean,byte),对象引用(refarence类型 不是对象本身,根据不同虚拟机实现,可能是指向对象起始化地址的指针,也可能是一个代表对象本身的句柄或者与对象相关的位置),returnAddress类型(该类型指向一条字节码的地址)
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值