jvm内存模型

程序计数器


特征:占用内存很小,线程私有,生命周期与线程相同。
作用:当前线程所执行的字节码的行号指示器,正在执行的虚拟机字节码指令的地址。
异常情况:此内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。


特征:线程私有,生命周期与线程相同,使用连续的内存空间。
作用:Java方法执行的内存模型,用于存储本地变量,操作栈等。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
配置参数:-Xss
异常情况:StackOverflowError和OutOfMemoryError


特征:线程共享,生命周期与虚拟机相同,可以使用不连续内存空间
作用:保存对象、数组。随着JIT编译器栈上分配,标量替换等优化技术的发展,这个也不是绝对了。
配置参数:
1
2
3
4
5
-Xms16m:堆内存初始值
-Xmx256m:堆内存最大值
-Xmn:堆内存新生代大小
-XX:NewRatio=2: ratio=old/new
-XX:SurvivorRatio=8:ratio=eden/survivor

异常情况:OutOfMemoryError

方法区


特征:线程共享,生命周期与虚拟机相同,可以使用不连续内存空间
作用:存储已被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码
配置参数:
1
2
-XX:PermSize=12M
-XX:MaxPermSize=64M

异常情况:OutOfMemoryError

运行时常量池


特征:方法区一部分,具备动态性
作用:存放字面量和符号引用
异常情况:OutOfMemoryError

直接内存


特征:非虚拟机规范定义,但使用频繁。
作用:主要在JAVA的NIO,比如文件流等
配置参数:默认=堆大小
异常情况:OutOfMemoryError

对象访问


对象访问的两种方式:句柄和指针
句柄:类似销售模式里面的代理模式,先访问一个中间变量,再通过该中间变量访问对象
指针:类似销售模式里面的直销模式,直接通过指针去访问对象

内存分配


对象优先在EDEN分配,大对象直接进入老年代,长期存活的对象将进入老年代,适龄对象也可能进入老年代。

新生代


新生代是类的对象创建、成长和死亡的区域,一个类的对象在这里产生,使用,最后被gc,结束生命。新生代分为两个部分:Eden Space和两个Survivor区域。
当Eden Space空间用完时,JVM将此区域仍然存活的对象移动到Survivor 0 区域,然后对Eden Space进行垃圾回收,
当Survivor 0 满时,存活对象移动到Survivor 1,当Survivor 1 慢时,则把仍然存活的对象移动到Tenured Space 老年代中。

老年代


存放从新生代中筛选后的java对象。

持久代


持久代是一个常驻内存区域,用于存放JDK本身所携带的Class等元数据,被加载进来的数据时不会被gc的,随JVM的关闭而释放内存。