深入理解Java虚拟机阅读心得21/4/21

Java虚拟机 自动内存管理机制

     对于Java程序员来说,因为有了虚拟机内存自动管理的机制,无需去为创建的每一个对象去写删除释放代码,不容易出现内存泄漏和内存溢出的问题,但是正因为不需要去关注这些,在追求高并发高性能的环境下,万一出现了以上的两个问题,如果不了解虚拟机管理内存的机制是如何的,那么找到问题的原因并解决将是一个非常困难的问题。

Java虚拟机会将管理的内存划分成几个不同的区域,分别是:虚拟机栈,本地方法栈,程序计数器,方法区,堆。

程序计数器区是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指令器,在我们编写的Java文件经过编译后都会生成一个class文件,其中的代码就是字节码,Java文件中每一个方法都只有两种结束的方式,要么是正常退出回复到程序执行该方法后应该执行的位置,要么是方法内发生错误抛出异常程序终止,而程序计数器区的作用就是记录当前程序执行到的位置,分支,循环,跳转,异常处理,线程恢复等都需要依赖计数器才能完成,由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个时期,一个处理器都只会执行一条线程中的指令,所以为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,各条线程的计数器互不影响,独立存储,所以程序计数器这一块的内存区域是线程私有的内存,如果线程正在执行的是一个Java方法,计数器中记录的是正在执行的虚拟机字节码指令的地址,而如果执行的是Native方法,这个计数器的值则为空,程序计数器的区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。

Java虚拟机栈也是属于线程私有的,它的生命周期与线程相同,其描述的是Java方法执行时的内存模型,每个方法在执行的同时都会创建一个栈帧用来存储局部变量表,操作数栈,方法入口等信息,每一个方法从调用到执行完成的过程,就对应一个栈帧在虚拟机中入栈到出栈的过程。局部变量表所需的空间内存在编译期间就已经完成分配并且固定,在Java虚拟机规范中,对于这个区域规定了有两种异常,如果线程请求的栈深度大于虚拟机允许的深度,就会抛出StackOverflowError异常,而如果虚拟机栈可以动态扩展,而在扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。``

本地方法栈与虚拟机栈类似,唯一的不同则是虚拟机栈是为虚拟机执行Java方法服务的,而本地方法栈则是为了给虚拟机执行Native方法服务,而在有的虚拟机中甚至将两块区域进行了合并,其抛出的异常类型也与虚拟机栈相同。

对于大部分应用来说,应该是内存中最大的一块,也是垃圾回收机制的主要管理区域,因此也被称为GC堆,堆在虚拟机启动时被创建,其唯一的作用就是存储实例对象,而在堆中也划分了很多区域,比如新生代老生代、Eden区等等,但无论如何划分,其中存储的都是实例对象,划分这些区域的目的只是为了更快的分配空间已经对空间进行垃圾回收处理。根据Java虚拟机的规范,堆可以处于物理不连续的内存空间上,只要逻辑上是连续的即可,在实现时,即可以是固定空间的,也可以是可扩展的,如果在堆中没有内存进行实例对象存储,并且无法再扩展,就会抛出OutOfMemoryError异常。

方法区和堆一样,是所有线程共享的区域,用来存储已被虚拟机加载的类信息,常量,静态变量,即使编译器编译后的代码数据,在Java虚拟机规范中将其描述为堆的一个逻辑部分,但其有一个别名“非堆”,目的应该是用于和堆区分开来,在该区域中进行的垃圾回收主要是回收常量池和对类型的卸载,当方法区无法满足内存分配时,会抛出OutOfMemoryError异常。

  • 1
    点赞
  • 1
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值