JVM之内存结构

前言

Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对数据进行了不同空间的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

具体划分为如下5个内存空间
虚拟机栈方法区程序计数器本地方法栈

image

1、程序计数器

每个线程拥有一个PC寄存器
在线程创建时创建
指向下一条指令的地址
执行本地方法时,PC的值为undefined
此区域是内存中唯一一块没有规定任何OutOfMemoryError(内存溢出)情况的区域,为什么?因为我们不需要操作该区域,该区域是内部维护的。

2、虚拟机栈

线程私有,生命周期和线程相同。
每个方法被调用的时候都会创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机中从入栈到出栈的过程。

在Java虚拟机规范中,对这个区域规定了两种异常情况:
(1)如果线程请求的栈深度太深,超出了虚拟机所允许的深度,就会出现StackOverFlowError(比如无限递归。因为每一层栈帧都占用一定空间,而 Xss 规定了栈的最大空间,超出这个值就会报错)
(2)虚拟机栈可以动态扩展,如果扩展到无法申请足够的内存空间,会出现OOM

3、本地方法栈

是为本地的native方法服务的,其他的都和虚拟机栈一样。

4、堆

线程共享的一块区域,用来存放对象实例的(由于现在有了逃逸分析技术,也可以将对象分配在栈上),该区域是垃圾回收的主要区域,垃圾回收主要是分代回收,有年轻代和老年代,堆可以是物理上不连续的区域,只要逻辑上连续即可。在堆中分配内存的方法有碰撞指针(前提是区域绝对规整,注意多线程同步问题,可以采用CAS原理加失败重试实现或者本地线程分配缓冲)和空闲列表(不是规整的内存,就是有一个表记录空闲的内存,然后分配后,从该表中去除),堆空间不足时会出现OutOfMemoryError异常。

逃逸分析技术是当虚拟机采用编译器执行代码的一种优化方案。
逃逸分析主要是分析对象的作用域,如果一个变量的作用域在方法体内,并且没有将该变量赋给方法体外的变量,那么这个对象就没有发生逃逸现象,为了提高性能,在栈上分配该对象的内存,当栈帧从Java虚拟机栈中弹出,就自动销毁这个对象。减小垃圾回收器压力。

5、方法区

线程共享的区域,存储JVM加载的类信息(类的版本,字段,方法,接口),常量,静态变量以及即时编译后的代码等数据。方法区还有一块运行时常量池,class文件中的常量池在类加载后就被放入运行时常量池,运行时常量池相对于class文件的常量池具有动态性,可以在运行期间通过intern将常量放入运行时常量池中,方法区空间不足时会抛出OutOfMemoryError异常。

特例

除了Java虚拟机规定的这几块区域以外呢,还存在一个堆外内存,即直接内存,直接内存能减少IO时的内存复制了,实现零拷贝,而且没有GC,减少了垃圾回收的工作,加快了复制的速度,该区域也难以控制,如果内存泄漏很难排查。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • JVM内存结构主要有三大块:堆内存、方法区和栈。堆内存是JVM中最大的一块由年轻代和老年代组成,默认比例是1:2;...
    小豆瓣的靳先生阅读 1,072评论 0 0
  • 对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug。同时,JVM也是面...
    Tank丶Farmer阅读 5,677评论 0 15
  • 内存溢出和内存泄漏的区别 内存溢出:out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,...
    Aimerwhy阅读 4,055评论 0 1
  • 第二部分 自动内存管理机制 第二章 java内存异常与内存溢出异常 运行数据区域 程序计数器:当前线程所执行的字节...
    小明oh阅读 4,911评论 0 2
  • 你的存在既有意义又无意义。 只不过是耳边的一阵清风,耳内的一丝乐声,潺潺如流水。 渐渐的,我不会经常分享给别人自己...
    沐清欤韵阅读 3,355评论 0 0