Java堆(Heap)
线程所共享资源,主要用于存储new出来的实例对象和数组
方法区(No-Heap)
运行时常量池:类信息、常量、静态变量、即时编译器编译后的代码等数据
线程运行的内存结构
java虚拟机栈
(1)局部变量表
存储局部变量。如果是基本类型直接存储;如果是对象和数组,仅仅存储指向他们的地址,而对象和数组本身存储到堆中。
f1(){
int i = 1;
Date date = new Date();
Long[] array = new Long[]{1L,2L};
}
i=1存储在局部变量表;date引用存储在局部变量表,date本身存储在堆;arrary引用存储在局部变量表,array本身存储在堆
(2)操作数栈
局部变量在运算过程中,使用的临时数据存储区域,可以看出操作数栈就是压栈和弹栈操作
(3)动态链接
指向方法所在类的常量池
(4)返回地址
并不是严格意义的结构,情况1:方法正常结束,返回一个return值给调用方;情况2:抛出异常,由调用方的异常处理模块处理
本地方法栈
和虚拟机栈类似,只不过是native方法
程序计数器
记录当前线程指令执行的位置,线程切换上下文恢复后,重新又从之前保存的位置开始执行
发生OutOfMemoryError异常
如果堆中没有内存分配实例,且堆也无法再扩展时候
当方法区无法满足内存分配需求时
当扩展虚拟机栈无法申请到足够的内存
发生StackOverflowError异常
线程请求的栈帧大于最大的栈深度。因为在java虚拟机栈中,一个方法就是一个栈,白话说就是调用太多方法
JVM内存结构图
堆空间细分
年轻代(New):年轻代用来存放JVM刚分配的Java对象
年老代(Old):年轻代中经过垃圾回收没有回收掉的对象将被Copy到年老代
New又分为几个部分:
默认大小比例:Eden:Survivor1:Survivor2 = 8:1:1
Eden:Eden用来存放JVM刚分配的对象
Survivor1,Survivor2:两个Survivor空间一样大,当Eden中的对象经过垃圾回收没有被回收掉时,会在两个Survivor之间来回Copy,当满足某个条件,比如Copy次数,就会被Copy到Old。显然,Survivor只是增加了对象在年轻代中的逗留时间,增加了被垃圾回收的可能性。
JVM的参数调优
-Xms设置堆的初始空间大小
-Xmx设置堆的最大空间大小
-XX:NewSize设置新生代初始空间大小
-XX:MaxNewSize设置新生代最大空间大小
-Xmn:相当于同时设置了NewSize和MaxNewSize的大小
-XX:PermSize设置永久代最小空间大小
-XX:MaxPermSize设置永久代最大空间大小
-Xss:设置每个线程的栈大小
例子:
-Xms128m
堆最初始为128M,默认为物理内存的1/64,最小为1M
-Xmx128m
堆最大值,默认为物理内存的1/4或者1G,最小为2M
-XX:MaxPermSize=256m
MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4
-XX:MaxNewSize=256m
新生成的对象,能占用内存的最大值
-XX:PermSize=256m
PermSize设置永久代内存初始值,默认是物理内存的1/64