JVM内存分配

一、前言

关于JVM内存分配一直有想法想自己整理一篇文档,之前总是查询别的博客,对于概念的理解和系统的知识梳理一直没有仔细整理过。所以整理这样一篇文章,夯实基础,后续会查漏补缺,也希望多多指正。

二、概述

众所周知,Java虚拟机在执行Java程序时会把所管理的内存分为若干个不同的数据区域(也称为运行时数据区),大致也划分为方法区(Method Area)、虚拟机栈(VM Stack)、本地方法栈(Native )、堆(Heap)、程序技术器(Progra Counter Register)等五部分。

                   JVM内存分配_第1张图片

三、详细描述:
概念、分配内出容

1、是虚拟机管理内存最大的一块,也是被所有线程共享的一块内存区域。对象实例及数组会在堆上进行内存分配,但也不是绝对。另外堆也是垃圾收集的主要区域,根据垃圾收集的分带收集算法,堆还可以细分为新生代和老年代。而在物理空间上堆处于不连续的内存空间中,只要是逻辑上连续即可,既可实现固态大小,也可以实现可扩展性(可配置-Xmx 和-Xms控制)。当内存不足无法完成实例分配,同时堆也无法进行扩展时会抛出OOM。

2、方法区,也是各个程共享的一块区域,主要存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。也被称为“永久代”,不过在不同的虚 拟机中这两者还是有本质的区别。方法区同样支持固定大小及可扩展性,还可以选择不实现垃圾收集。同时也会出现OOM的异常。

运行时常量池也是方法区的一部分,存放编译期产生的各种字面量和符号引用,常量池受方法区内存限制,当无法扩展时会抛出OOM。

3、虚拟机栈,是线程私有的。在方法执行时会创建一个栈帧,每一个方法从调用到执行完成的过程也就是一个栈帧在虚拟机中出栈入栈的过程。虚拟机栈在编译器存放了基本数据类型,对象引用及局部变量。要注意的是在基本数据类型中long和double类型的数据会占用两个局部变量的空间,其余只占用一个。在异常情况中与堆相比除了因固定长度时(也支持动态扩展)无法扩展申请足够内存会抛出OOM还有因线程请求的栈深度大鱼虚拟机所允许的深度会抛出StackOverflowError异常。

4、本地方法栈 与虚拟机栈发挥作用相似,虚拟栈为执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用的Native服务。sun HOST POST 把二者合二为一,同虚拟机栈一样也会抛出OOM和StackOverflowError异常。

5、程序技术器是唯一一个没有任何规定OOM情况的区域,是一块比较小的内存空间。每条线程都需要一个独立的程序计数器,来保证线程切换后能恢复到正确的执行位置,在字节码解释器工作就是通过改变这个技术器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等功能。线程正在执行一个Java方法,计数器记录的是正在执行的虚拟机字节码指令地址,而如果正在执行Native方法,则技术器为空。

扩展 在JVM虚拟中还有一个内存既不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义饿内存区域,但是使用频繁,也会产生OOM异常。在引入NIO时为了避免Java堆和Native堆中来回复制数据,从而直接分配的堆外内存。本机直接内存不会受到Java堆大小的限制,受本机总内存影响。在服务器管理员在配置虚拟机参数时,会根据实际配置-Xmx等参数信息,但经常忽略直接内存,会出现各个内存区域总和大于物理内存限制,从而在动态扩容时出现OOM的情况。

你可能感兴趣的:(JVM)