JVM(二)- 自动内存管理(一)- 运行时数据区
目录一、JVM运行时数据区1、程序计数器2、虚拟机栈(stack)1)、局部变量2)、操作数栈3)、动态链接4)、出口3、本地方法栈(Native Method Stack)4、方法区5、堆(Heap)6、直接内存一、JVM运行时数据区Java程序运行时,会基于类加载机制将类文件加载到JVM,并...
目录
一、JVM运行时数据区
Java程序运行时,会基于类加载机制将类文件加载到JVM,并将类中的信息分解后放置到JVM的各个模块,以提供运行。程序(Java类)由数据、指令和控制(return等)组成。下面是JVM运行时数据区:
1、程序计数器
当前线程正在执行Java方法时,计数器存储的当前方法正在执行的字节码指令的地址和行号;若当前线程正在执行Native方法时,计数器存储的值为Undefined。并且程序计数器是唯一一个不会涉及OutOfMemoryError的区域。
2、虚拟机栈(stack)
虚拟机栈用于存储当前线程正在运行方法的数据、指令和返回地址。我们大多数情况下关注的是虚拟机栈中的局部变量表,局部变量表所需的内存控制的编译器已经确定,当进入一个方法时,所需的局部变量槽(Slot)已经确定(double和long占用两个槽)。
当线程请求的栈深度大于虚拟机运行的最大深度,则会抛出StackOverflowError;虚拟机栈动态扩展时(现在大部分Java虚拟机的虚拟机栈都支持动态扩容,少部分不支持),若无法申请到足够的内存空间,则会抛出OutOfMemoryError。
1)、局部变量
局部变量分为基本类型和引用类型:基本类型直接进行存储,并且long和double类型会存储两个局部变量空间(Slot);引用类型会则:1、指向Heap中的指针、对象的句柄或者位置 2、returnAddress地址(返回地址类型)。内存空间一经过分配就不会再进行改变,包括运行期间不能进行调整。
2)、操作数栈
出栈和入栈
3)、动态链接
常量池中查找父类引用指向子类对象的真实实例对象。
4)、出口
return、try catch 等控制程序
3、本地方法栈(Native Method Stack)
本地方法栈除了处理对象(native方法)不同,其他与虚拟机栈一致,并且在HotSpot中直接将两个进行合并,所以该部分也可能包StackOverflowError和OutOfMemoryError(原因与虚拟机栈相同)。
4、方法区
方法区与永久代是不完全等同的,但是很多时候为了方便理解,基本都理解为一致。方法区与堆一样:可以是非连续的内存空间,可以设置孤独的内存大小或者设置可以扩展的内存大小,可以不实现垃圾回收器。
1)、类信息 存放类的版本号、字段、方法等信息
2)、常量(常量池)
常量池并不是在编译器存储之后后续就不会动态扩展的区域,比如在运行期间String的intern()方法可以将常量放入常量池中,所以也会存在OutOfMemoryError问题。
3)、静态变量
4)、JIT(just-in-time ) 动态代理时候动态生成的代码
5、堆(Heap)
Java堆(Heap)与方法区是线程共享的,跟随Java虚拟机的生命周期。Java的一切都是对象,所有对象实例及数组都会分配在堆中(JIT、逃逸分析除外)。堆在G1垃圾回收器之前,都是按分代进行收集,可以理论上将堆分为新生代、老年代、永久代,Eden区、From Survivor空间、To Survivor空间等。Java堆的划分主要是为了更快的分配对象(new的时候)、和对使用完的对象的内存进行回收。从内存分配角度,Java的线程共享区可以分配出多个Java线程的私有缓存空间TLAB(Thread Local Allocation Buffer)。
Java虚拟机可以通过(-Xms、-Xmx)控制初始化内存和最大内存的大小,但是当在分配对象时(分配对象规则则是后面的内容)空间不够,并且不能再进行扩展时,则会在该区域抛出OutOfMemoryError异常。
6、直接内存
直接内存并不是运行时数据区的一部分,但是也是Java操作内存的一种方式。JDK4中引入New Input/Output类,可以使用Native函数直接分配堆外内存,目的是可以不用在本地方法栈和虚拟机栈中复制数据。虽然,不会受到JVM堆初始化和最大内存设置的限制,但是会受限于本机内存的限制,若堆内存分配空间过大,该部分没有内存可以用,也会照成OutOfMemoryError。
二、运行时数据区与内存溢出异常
由上面可知,运行时数据区与内存溢出、栈异常的关系如下:
三、JVM内存模型(JMM)
由于对象的生命周期是不一样的,所以需要对JMM进行分代。JMM分为新生代、老年代和永久代(在JDK1.8将永久代替换为Meta Space,一个可以无限扩展的内存空间),并且新生代与老年代为1:2,因为需要做内存担保。新生代为分eden区、S0区(from Survivor)、S1(to Servivor)区并且比例为8:1:1。根据计算得知,98%的对象会在minor gc的时候会被回收掉。
四、JVM常用配置参数
1、jvm配置
XX比X的稳定性更差,并且版本更新不会进行通知和说明。
1、-Xms s为strating,表示堆内存起始大小
2、-Xmx x为max,表示最大的堆内存
3、-Xmn n为new,表示新生代大小
4、-XX:SurvivorRator=8 表示堆内存中新生代、老年代和永久代的比为8:1:1
5、-XX:PretenureSizeThreshold=3145728 表示当创建(new)的对象大于3M的时候直接进入老年代
6、-XX:MaxTenuringThreshold=15 表示当对象的存活的年龄(minor gc一次加1)大于多少时,进入老年代
7、-XX:-DisableExplicirGC 表示是否(+表示是,-表示否)打开GC日志
2、对象进入老年代的条件
1、-XX:PretenureSizeThreshold=3145728 表示当创建(new)的对象大于3M的时候直接进入老年代
2、-XX:MaxTenuringThreshold=15 表示当对象的存活的年龄(minor gc一次加1)大于多少时,进入老年代
3、当同年龄的所有对象的大小总和 > Survivor空间的一半 ,则也会进入老年代
更多推荐
所有评论(0)