JAVA内存管理--java运行数据区

JAVA内存管理:

C/C++开发者对内存管理领域即是皇帝又是劳动人民,因为他们对内存拥有绝对的权限,但是每一单元的内存又必须对他们负责到底.

JAVA开发者不需要对内存进行周密的管理,统一交由虚拟机管理,这样近可能的为开发节省了时间,并且因为大多数人对内存的不熟悉,交给虚拟机管理可能性能更高.但是如果一旦发生内存相关的错误,比如溢出,如果对虚拟机怎么管理内存的不了解,那么解决错误可能将是一个难点.

JIT:just-in-time,第一次运行时编译,也叫及时编译或者动态编译

AOT: ahead-of-time,静态编译,事前编译

JAVA运行时数据区

下面是《java虚拟机规范(JAVA SE 7版)》将虚拟机运行时区域划分为如下图所示,那么为何会如此分配,就是JMM的规则定义的了.

 

运行时数据区本身也是内存中的一部分,不是独立于内存之外的其他区域.

程序计数器:

①是一小片内存,如下图所示,存储了程序中的指令执行顺序,或者理解为行号(下图把数字想象成代码的行号第6行执行之后执行了第9号,可能是遇到了一个判断之类的,后面9,10,11,12可以想象是遇到了一个循环),字节码解释器通过这个程序计数器来选择下一条要执行的指令,判断、循环、跳转、异常处理、线程恢复等都依赖这个计数器完成.

②而且这片区域是线程独立的,不会被其他线程共享,假如CPU每个时间单元只能执行一个指令,而计数器就记录这些指令的执行顺序,那么CPU切换到其他线程的时候是不是需要知道它之前执行到那一条线程的那个指令了?所以这个区域是线程私有的.也就是说这个区域可能会存放多个程序计数器,而每个计数器都是队友线程独立的.

③如果线程正在执行一个java方法,那么这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果线程正在执行一个Native方法,那么这个计数器值为空(Undefined).此内存区域是在JMM规则中唯一一个不会出现OutOfMemoryError的区域,不会出现内存溢出.

 

虚拟机栈:

①线程在执行方法时,首先会在此区域创建一个栈帧(Stack Fram),可以理解为一个栈帧就对应着一个方法的所有信息,局部变量表、操作数栈、动态链接、方法出口等信息.

②但是方法的参数并不在栈帧中,而是在当前方法的调用者的栈帧中.

③因为java申明变量时需要指定类型,所以局部变量表的大小会在编译时就能够确定,在执行方法创建栈帧的同时,这个局部变量表的大小就是固定的,不会改变,而其他信息可能会动态扩展,如果栈中有很多的栈帧,而且一直需要动态扩展,那么可能会报出OutOfMemoryError异常.而且栈的深度(栈帧数量)是固定的,就算可以改,但是改变之后还是固定的.那么当栈中的栈帧达到一定深度(数量)后会出现StackOverFlowerError异常.所以大家应该知道没有出口的递归报错的原因了嘛?

 

 

 

本地方法栈:本地方法栈与虚拟机栈类似,只不过虚拟机栈中的栈帧方法是普通方法,而本地方法栈中的是Native方法,因为本地方法不会限制编制语言,数据结构,数据类型等,自由度较高.

 

堆:

①所有对象都存在堆中,但是随着JIT的发展与逃逸分析技巧成熟,”所有”就不那么绝对了.

②堆是多有线程共享的,但是堆中可能会出现线程私有缓冲区(Thread Local Allocation Buffer TLAB),不过这个缓冲区放的还是对象.只是这个缓冲区不是线程共享的而已.

③堆可以是物理上不连续的内存,只要逻辑上联系就行.就像磁盘一样,你可以把两块磁盘分配为D盘.

④当存储的对象足够多时,同样可能抛出StackOverFlowerError异常.

 

方法区:

①方法区也是线程共享的.

②存储的是类信息、常量、静态变量、JIT后的代码等数据.

③属于堆的一个逻辑部分,但是他有个别名叫做non-heap(非堆),还是为了将它从堆中剥离出来.它还有个别名叫永久代(HotSpot虚拟机这么叫),因为堆可以划分为新生代、老年代.也许是为了与之对比,因为方法区中的数据一般不会被回收,当然并不是绝对的.只是回收机制特别复杂.

④当方法区的内存无法满足分配时,同样可能抛出StackOverFlowerError异常.

运行时常量池:

①运行时常量池是方法区的一部分,用于存放在编译期生成的字面量比如:10,”hello world”,true等和符号引用.

②运行时常量池除了装载编译期间产生的那些常量外,同样允许在允许期间装载常量,比如String类的intern()方法(该方法会去常量池中找是否存在,存在就返回这个引用,不存在就创建一个字符串对象,并将这个引用放进常量池)

③当内存无法满足分配时,同样可能抛出StackOverFlowerError异常.

本地方法库:本地方法库不是java运行数据区的一部分,也不是java虚拟机规范中的定义的区域,但是java程序运行时也会频繁使用,也会抛StackOverFlowerError异常.JDK1.4中定义了NIO,引入通道(Channel)与缓冲区(Buffer)来操作I/O,可以使用Native函数库来直接分配堆外内存.然后通过存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微笑い一刀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值