jvm的内存模型和结构

jvm的内存模型和结构

1.程序计数器

他是一块较小的内存空间,可以看做是当前线程所执行字节码的行号指示器,字节码解释器通过改变程序计数器内的数值来选取下一条需要执行的指令,分支,循环,跳转,异常处理,线程恢复等基础功能都依赖程序计数器来实现.

Jvm多线程是通过分配处理器的执行时间来实现的,在任何一个确定的时间,一个处理器只会执行一个线程中的指令,因此,每个线程都有属于自己的程序计数器,各个线程的程序计数器互不影响,我们称这类内存为’私有内存’.

如果一个线程正在执行一个java方法,这个程序计数器内存的是正在执行的字节码指令地址,但如果执行的是native方法,则程序计数器内存的是空(Undefined),此内存区域是jvm规范中中唯一个没有规定内存溢出(OutOfMemoryError)情况的区域.

2.jvm栈

Jvm栈也是线程私有的,它的生命周期是随着线程的创建而创建,销毁而销毁.jvm栈是java方法执行的内存模型,每个java方法执行时都会创建出一个栈来存储局部变量,操作栈,动态链接,方法出口等信息,每个java方法的调用到执行完成的过程,就代表着这个jvm栈从’入栈’到’出栈’的一个过程.

通常所指的栈内存就是指的是jvm栈中局部变量表部分,局部变量表中存放了编译器可知的各种基本数据类型 ( boolean、byte、char、short、int、float、long、double ) ,引用对象   ( reference 类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置 )和returnAddress类型(指向了一条字节码指令的地址)。其中64单位长度的long和double会占用两个局部变量空间(slot),其他占用一个局部变量空间,局部变量表所需的内存空间在编译器内分配完毕,当进入一个方法时,这个方法需要分配的大多数局部变量空间是确定的,在方法运行时不糊改变局部变量表的大小,在jvm规范中,在这个区域规定了两种异常情况,①如果线程请求的栈深度大于jvm所允许的深度,则抛出StackOverflowError(栈溢出)异常

②如果jvm栈可以动态扩展,但在扩展时无法申请到足够的内存,则抛出OutOfMemoryError(内存溢出)异常

3.本地方法栈

本地方法栈和jvm栈类似,本地方法栈是为jvm中的native方法做服务,jvm规范中没有对于本地方法栈做强制规定,本地方法栈也有StackOverflowError(栈溢出)和OutOfMemoryError(内存溢出)的异常

4.java堆

对于大多数应用来说,java堆是jvm所管理的内存最大的一块,是所有线程共享的一块内存区域,在jvm启动时创建,此内存区域的唯一目的就是存放对象实例.,如果在堆中没有内存完成实例分配,并且堆也无法在扩展时,则会抛出OutOfMemoryError(内存溢出)异常.

5.方法区

方法区和内存堆一样,是所有线程共享的区域,它用于存储已被jvm加载的类信息,常量,静态变量,及时编译后的代码等数据,方法区无法满足内存分配需求时,也会抛出OutOfMemoryError(内存溢出)异常

6.运行常量池

运行常量池是方法区的一部分,class文件中除了有类的版本,字段,方法,接口等描述信息以外,还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容在类的加载后被存放在方法区的运行常量池内,jvm对于class文件的每一部分的格式都有严格的规定,但对于运行常量池的细节没有限制,但运行常量池也是属于方法区的一部分,当运行常量池无法在方法区内申请到内存时,就会抛出OutOfMemoryError(内存溢出)异常

7.直接内存

直接内存不是jvm运行时数据区的一部分,也不是jvm规范中定义的内存区域,但这部分内存也被频繁的使用,也可能导致OutOfMemoryError(内存溢出)

在jdk1.4中新加入nio类,引入一种基于通道和缓冲区的i/o方式,他可以是native函数库直接分配到堆外内存,然后通过一个内存在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作,这样一来能再一些场景中显著的提高性能,因此避免了java堆和native堆中来回复制数据.

本地直接内存不会受java堆大小的限制,但会受本机总内存大小的限制,服务器管理员配置jvm参数时会经常忽略掉直接内存的配置,使得各个内存区域的总和大于物理内存限制,从而导致动态扩展时出现OutOfMemoryError(内存溢出)的异常

 

我们在创建一个对象时:

Object obj = new Object();

‘Object obj’这部分语义反映到java栈的本地变量表中,作为一个reference类型数据出现, reference类型是指向一个对象的引用.有两种方式去定位①直接指针访问[速度快,节省定位时间]②在java堆内存中划出一块作为句柄池, reference内存句柄地址,句柄中包含对象实例数据和类型数据各自的具体地址信息[稳定,对象被移动时, reference本身不需要被修改]

‘new Object()’这部分语义将会反映到java堆总,形成一块存储了Object类型所有实例的数据值得结构化内存

 

这是本人学习jvm的一些笔记和觉得需要知道的知识点,希望对于大家有所帮助!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值