JVM内存结构
Heap Space:
堆内存(Heap Space)是由Young Generation和Old Generation组成,而Young Generation又被分成三部分,Eden,From Survivor和To Survivor,默认比例为8:1:1
堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,大部分对象实例都在这里分配内存。
堆是垃圾收集管理的主要区域,如果在堆内存耗尽,并且无法再扩展时,将会抛出OutOfMemoryError异常。
Method Area:
又称为非堆内存。在HotSpot虚拟机上属于Permanent Generation。
方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,是线程共享的区域。
栈又分为java虚拟机栈和本地方法栈主要用于方法的执行。
这个区域的内存回收主要是针对常量池的回收和对类的卸载,一般不发生。
根据Java虚拟机规范的规定,当方法区耗尽时,将抛出OutOfMemoryError异常。
Native Area:
Native方法区,包含PC,栈及C/C++运行环境。
PC(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
JVM Stacks是线程私有的,它的生命周期与线程相同。虚拟机栈是Java方法执行的内存:每个方法被执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。
局部变量表存放了编译期可知的各种基本数据类型、对象引用和Return Address。栈帧所需的内存空间在编译期间完成分配,运行期间不会改变局部变量表的大小。
JVM规范中规定了栈的两种异常状况:
1.如果栈的深度大于所允许的深度,将抛出StackOverflowError异常,如死递归;
2.如果内存耗尽,则抛出OutOfMemoryError异常。
Native Method Stacks与JVM Stack类似,是保存Native方法栈。
内存调优:
jvm参数:-Xms, -Xmx ,-Xmn ,-XX:SurvivorRatio,-XX:MaxTenuringThreshold,-XX:PermSize,-XX:MaxPermSize
-Xms -Xmx ,为避免运行时JVM不断调整堆内存大小,通常设置为相同的值,该值决定了JVM heap所能使用的最大内存
-XX:PermSize、-XX:MaxPermSize 用来控制非堆内存的大小,通常设置为相同的值
-Xss 每个线程的栈大小
-Xmn 决定了YG的大小,Eden、FS、TS三个区域的比例可以通过-XX:SurvivorRatio来控制,默认为8:1:1
-XX:MaxTenuringThreshold 设置对象在经过多少次minor GC之后进入老年代,此参数只有在Serial 串行GC时有效
1.新生代设置调小,会使minorGC次数增加,对象年龄增长变快,使其提前进入老年代,老年代内存增长,会触发FullGC
2.新生代设置过大,会导致老年代变小,当其内存耗尽,会触发FullGC
监测工具(JDK自带):
jconsole
图形界面及命令行的java性能分析工具
http://docs.oracle.com/javase/6/docs/technotes/guides/management/jconsole.html
jvisualvm
jconsole的升级版
jinfo
可获取详细的java配置信息
格式: jinfo pid
jmap
可监测运行中的jvm物理内存的占用情况
如:jmap -heap pid 打印heap信息
jmap -dump:format=b,file=heap.hprof pid 输出dump文件
jmap -h 查看帮助
jstack
监测jvm中当前所有线程的运行情况和线程当前状态
jstat
可利用了JVM内建的指令对Java程序的资源和性能进行实时的命令行的监控,包括各种堆和非堆的大小及其内存使用量、classloader、compiler、垃圾回收状况等。
格式:jstat -option -t -h pid interval count
如: jstat -printcompilation -h15 pid 500 500
参数说明
-h15 每隔15行打印一次标题
interval 每隔500ms打印一次
count 共打印500次
options:
class 统计class loader行为信息
compiler 统计编译行为信息
gc 统计jdk gc时heap信息
gccapacity 统计堆内存不同代的heap容量信息
gccause 统计gc的情况(同-gcutil)和引起gc的事件
gcnew 统计gc时新生代的信息(相比gcutil更详细)
gcnewcapacity 统计gc时新生代heap容量
gcold 统计gc时,老年区的情况
gcoldcapacity 统计gc时,老年区heap容量
gcpermcapacity 统计gc时,permanent区heap容量
gcutil 统计gc时,heap情况
printcompilation 统计编译行为信息
测试堆内存溢出:
新建文件MemTest.java,输入代码:
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class MemTest { public static void main(String[] args) { int count = args.length == 1 ? Integer.parseInt(args[0]) : 30; List<List> list = new LinkedList<List>(); long max = Runtime.getRuntime().maxMemory(); long totle = Runtime.getRuntime().totalMemory(); int i = 0; while (true) { list.add(new ArrayList<Integer>(1024)); if (i++ > count) { long free = Runtime.getRuntime().freeMemory(); System.out.println("max:" + max / (1<<20) + "m totle:" + totle/(1<<20) + "m free=" + free/1024 + "kb"); i = 0; } } } }
输入:
javac MemTest.java
java -Xms10m -Xmx10m MemTest 50
输出:
end