Java运行时数据区

一.概述
    1.1.
Java程序员把内存控制权力交给了Java虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那排错就会非常困难。
二.运行时数据区
    虚拟机把它所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,以及创建销毁的时间。有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。
    2.1 
    程序计数器(线程私有?线程轮流切换使用一个处理器,在任意一个确定的时刻,一个处理器只会执行一条线程的指令,因此,为了线程切换后能恢复到正确的执行位置):当前线程所执行的字节码的行号指示器。
    2.2 
    Java虚拟机栈(线程私有)(为虚拟机执行Java方法而服务)
        生命周期和线程相同。描述的是方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法被调用至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

    Java内存粗糙的分为堆和栈,所指的栈其实就是这里的虚拟机栈,或者说是虚拟机栈中的局部变量表(各种基本的数据类型,对象引用(不同于对象本身,根据不同虚拟机的实现,他可能有所不同))。64位长度的Long和Double会占两个局部变量空间,其余数据类型各占一个。
    局部变量表所需的内存空间在编译时期完成分配,当进入一个方法时,每个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
    
    如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出stackoverflow异常(栈溢出),如果虚拟机栈允许动态扩展,当扩展无法申请到足够的内存会抛出OutOfMemoryError(内存溢出)
    2.3 本地方法栈(为虚拟机所使用到的Native方法服务)
        虚拟机规范中对本地方法栈中的方法使用的语言 ,使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由的实现它。甚至有的虚拟机直接将两者合二为一。本地方法栈也会抛出StackOverFlow和OutOfMemoryError异常。
    
    StackOverflowError:递归过深,递归没有出口。
    OutOfMemoryError:JVM空间溢出,创建对象速度高于GC回收速度。
    2.4 Java堆(所有对象实例和数组都要在堆上分配)
    对于绝大多数应用来说 ,Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建。(目的:存放对象实例)

    Java堆是垃圾回收器管理的主要区域,很多时候也被称为GC堆
    内存回收的角度:由于现代收集器基本上采用的是分代收集算法,所以Java堆还可以细分为:新生代和老年代;再细致一点有Eden空间,From Survivor空间,To Survivor空间等。
    内存分配的角度:线程共享的Java堆可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB),无论如何划分,都与存放内容无关,无论哪个区域,存放的都是对象实例。进一步划分是为了更好的分配和回收内存。


    Java堆可以处于物理上不连续的内存空间,只是逻辑上连续即可。在实现时,既可以实现成固定大小的,也可以是扩展的。
    如果在堆中没有完成实例的分配,并且堆也无法扩展时,将会抛出OutOfMemoryError。

    2.5 方法区 与Java堆一样,是个线程共享的内存区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。Java虚拟机规范把方法区描述为堆的一个逻辑部分(存放对象的类型数据,如对象类型,父类,实现的接口,方法等),但它却有一个别名,目的是与堆区分开来。
    HotSpot虚拟机把方法区成为永久代,本质上并不等价,仅仅是因为HotSpot设计团队选择把GC分代收集扩展至方法区,或者说用永久代实现方法区。


    Java虚拟机规范对这个区域的限制非常宽松,相对而言,垃圾收集行为在这个区域还是比较少见的,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,尤其是对类型的卸载,条件是非常苛刻的,但这部分回收是非常有必要的。
    2.6 运行时常量池
     是方法区的一部分。Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后存放在方法区的运行时常量池中。
        Jav虚拟机对Class文件每一部分(自然也包括常量池)的格式都有严格的要求,每一字节用于存放哪种数据结构都必须符合上述规范要求,这样才会被虚拟机认可,装载,执行。但对于运行时的常量池并没有作任何细节的要求,一般来说,除了保存Class文件中描述的引用符号外,还会把翻译出来的直接引用也存储在运行时常量池中。

        
    重点:  运行时常量池相对于Class文件常量池的另外一个重要特性是具备动态性,Java语言并不要求常量只能在编译时产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用较多的便是String的intern()方法。
        既然运行时常量池也是方法区的一部分,自然也受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOofMemoryError异常。

     2.7 直接内存(不属于虚拟机运行时数据区的一部分,也不是Java虚拟机规范定义的内存区域),但是这部分内存也被频繁使用,而且也可能导致OutOfMemoryError异常。

    在JDK1.4中新加入了NIO类,引用了一种基于通道于缓冲区的I/O方式,它可以是Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样做能显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

    显然,本机直接内存大小不会受到堆中内存的限制,但是会受到本机总内存(RAM及SWAP区或者分页文件)的大小和处理器寻址空间的限制。超过本机内存限制,动态扩展是页也会出现OutOfMemoryError异常。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值