这篇文章主要讲解了“jvm内存结构的原理及应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“jvm内存结构的原理及应用”吧!
创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站设计、成都网站制作、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的尼玛网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
jvm内存结构主要包括:方法区、堆、虚拟机栈、本地方法栈、程序计数器等五大部分, 下面我们来具体看一下每一个部分。
作用:
虚拟机栈描述的是java方法执行的动态内存模型,通过进栈、出栈来实现方法的调用结构。
分析:
栈结构的特点是后进先出,方法调用的过程也是后调用的方法返回结果后,先调用的方法再接着执行,你是干柴,我是烈火。你是鱼儿,我是小河。(此处不知道是蛋孵化了鸡,还是鸡生出了蛋)
以methodA调用methodB为例,来看一下方法栈的执行过程
首先是主方法进入空栈(图中免去了这一步),主方法中调用methodA --》 methodA入栈 --》 methodA调用methodB --》 methodB入栈 --》 methodB执行完毕,出栈并返回返回值 --》 methodA执行完毕,出栈并返回返回值 --》主线程执行完毕并出栈(图中免去了这一步)--》程序执行完毕。
那么methodA、methodB中到底包含了哪些内容呢?
我们不如从方法定义的角度来思考一下,编写程序时,里面经常出现的几个要素无外乎:变量、控制结构(循环、分支)、函数调用(也可以叫方法),函数其实就是用一定的控制结构来操作变量,中间穿插着其他函数的调用,分支结构主要控制的是程序执行到哪一行,这个由我们后面1.5章节要讲到的程序计数器来实现,函数调用层次如上面所说由虚拟机栈来支持,而变量以及方法的出口就是methodA、methodB中的主要内容。
methodA、methodB在虚拟机栈中叫做栈帧,栈帧中包括变量(局部变量表-基本类型、对象引用-对象内存地址等)以及返回值地址等信息,可以看出栈帧中包含的内容是编译器就可确定大小的,当进入一个方法时,需要分配多大的局部变量空间是完全确定的,在运行期中不会改变局部变量表的大小。
此区域可能出现的异常:
栈是有深度的,方法调用层次超过栈的深度,就会出现StackoverflowError,一般是递归调用时,基线条件不合理时,容易出现此问题。
当栈的深度增大时,所需要的局部变量表空间也随之增长,当超过一定界限时,会出现OutOfMemoryError异常。
作用:
本地方法栈与虚拟机栈的区别是调用的是不同类型的方法,本地方法栈用于记录native方法的调用,本地方法栈中未对native方法实现语言、数据结构等做强制规定,主要由虚拟机自己定义并实现。
注:
由于本地方法栈和虚拟机栈的作用非常相似,因此部分虚拟机的实现中,就将这两块区域合并成了一个区域,例如比较常用的Hotspot。
此区域可能出现的异常
与虚拟机栈相同,此区域也有可能出现StackoverflowError或OutOfMemoryError。
作用:
堆是jvm是管理的内存中最大的一块,此区域只有一个作用就是存放对象实例。(java是面向对象语言--》堆用于存放对象实例 --》堆占用空间最大,嗯,没毛病铁子。)
注 :
由于此区域占用内存空间最大,而且对象的创建与销毁是比较频繁的,那内存空间不够用了怎么办?跟杀猪挑最肥的宰是一个道理,此区域是垃圾回收的主要区域。java为我们省去了代码层手动释放内存的工作,通过垃圾回收器来实现自动化的内存回收(《7天精通java》:《21天c++从入门到入土》,知道自动垃圾回收的重要性了吧)
此区域可能出现的异常:
为对象分配空间时,内存不足,会出现OutOfMemoryError(敲黑板)。
对应的排查策略:配置参数-XX:+HeapDumpOnOutOfMemoryError,这样虚拟机在出现此异常时,会生成内存堆存储快照,使用工具Eclipse Memory Analyzer或jprofiler,可以分析某些对象占用空间百分比,快速定位到问题,如果代码存在问题,例如不停的创建某些对象,但并不释放,那就要通过修改代码来解决问题,如果代码不存在问题,就需要通过加大物理内存,调整jvm堆参数来增加堆大小。(-Xms 堆初始化大小,-Xms 对空间最大大小,实际配置过程中,一般设置成一样的大小,避免出现内存抖动,影响稳定性)
作用:
方法区主要用于存取类信息、常量、静态变量、运行时常量池等。
分析:
运行时常量池用于存取字面量和符号引用,当使用双引号声明String变量时,此变量并不是开辟到堆空间当中,而是开辟到方法区中的运行时常量池中的,运行时常量池不仅可以在编译期产生,也可以在程序运行期间,动态产生,例如String中的intern方法,就是在程序运行状态中将字符串值放到运行时常量池中的。
此区域可能出现的异常:
此区域在内存不足时,也会出现OutOfMemoryError异常。
作用:
程序计数器主要是用于记录当前线程所执行的字节码的行号指示器,即当前线程执行到了哪一行,由于功能比较简单,所以与其他几个区域相比,内存空间占用的非常小。
此区域可能出现的异常:
程序计数器的作用决定了在此区域中不会出现由程序本身导致的异常,如果此处出现异常,是jvm本身的设计缺陷。
注:
如果线程执行的是java方法,计数器对应的是字节码指令的地址,但是如果是native方法,底层是非java实现的,此时计数器对应的值是undefined
引申:
说到了程序计数器,在部分编程语言中,是支持goto关键字的,goto可以让程序直接跳转到指定行,java是不支持goto的,但是把goto作为了保留字,即java不支持此种语法,但是也不让开发者去定义为变量,防止后续java发展过程中,加入goto关键字后,导致部分程序运行异常。
上面五个区域中,方法区和堆是线程共享的区域,这两个区域中放置的内容是与线程无关的,任意一个线程都可能会访问到这两块区域中的内容。
对于每个线程来说,它的调用方法栈应该是独属于某个线程的,如果多个线程共用一个方法栈那程序的执行顺序是无法得到保障的,线程执行到哪一行应该也是唯一的,因此方法栈、程序计数器是线程独占的。
感谢各位的阅读,以上就是“jvm内存结构的原理及应用”的内容了,经过本文的学习后,相信大家对jvm内存结构的原理及应用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!