1. 概述
java与c++之间有一堵由动态内存分配和垃圾收集技术所谓成的“高墙”,墙外面的人想进去,墙里面的人却想出来。
2. 运行时数据区域
jvm在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。如下图:
2.1 程序计数器(PCRegister)
首先它是线程私有的。另外它是一块较小的内存模型,可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
此区域是唯一一个不会出现OOM(out of memory)情况的区域。
2.2 java虚拟机栈(VM Stack)
也是线程私有的,它的生命周期与线程相同。Java Virtual Machine Stacks 描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储【局部变量表】、【操作数栈】、【动态链接】、【方法出口】等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。
局部变量表存放了编译期可知的各种基本数据类型、对象应用类型。局部变量表所需的内存空间在编译期间完成分配,方法运行期间不会改变。
两种异常状况:StackOverflowError, OutOfMemoryError。
2.3 本地方法栈(Native Method Stack)
本地方法栈为虚拟机使用到的Native方法服务。
也抛两种异常:StackOverflowError, OutOfMemoryError。
2.4 Java堆(java heap)
Java Heap是jvm所管理的内存中最大的一块,是被所有线程共享的一块内存区域,唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java Heap是垃圾收集器管理的主要区域,也被称作GC堆。
Java Heap一般可以分为以下三个部分:(年轻代,老年代,永久代)
Young 年轻区
Young区被划分为三个区:Eden区、两个大小严格相同的Survivor区(From、To) , 其中Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Young区间变满的时候,minor GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。
JVM提供了相应的参数来对内存大小进行配置
◆ Total Heap
-Xms :指定了JVM初始启动以后初始化内存
-Xmx:指定JVM堆得最大内存,在JVM启动以后,会分配-Xmx参数指定大小的内存给JVM,但是不一定全部使用,JVM会根据-Xms参数来调节真正用于JVM的内存
-Xmx -Xms之差就是三个Virtual空间的大小
◆ Young Generation
-XX:NewRatio=8意味着tenured 和 young的比值8:1,这样eden+2*survivor=1/9
堆内存
-XX:SurvivorRatio=32意味着eden和一个survivor的比值是32:1,这样一个Survivor就占Young区的1/34.
-Xmn 参数设置了年轻代的大小
◆ Perm Generation
-XX:PermSize=16M -XX:MaxPermSize=64M
Thread Stack
-XX:Xss=128K
2.5 方法区(Method Area)
也称永久代(PermGen)。java虚拟机把方法区描述为堆的一个逻辑部分,但是它却有一个别名:Non-Heap,目的是与heap分开。
与堆一样,是各个线程共享的内存区域,存储被虚拟机加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码。
相对而言,垃圾收集行为在这个区域是比较少出现的。
2.6 运行时常量池(Runtime Constant Pool)
它是方法区的一部分,用于存放编译器生成的各种字面量和符号应用。
2.7 直接内存(Direct Memory)
并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。