Java数据区域(内存区域):
1. 程序计数器(Program Counter Register) :存放当前正在被执行的Java 字节码操作指令的地址
2. Java虚拟机栈(Java VM Stack) :存储线程在执行过程中的参数,返回值,以及中间结果等
3. Java堆(Heap) : 存储Java类实例或数组的
4. 方法区(Java VM Method Area) :存储类型相关的信息, 如该类型的常量池,字段或方法信息
5. 常量池(Runtime Constant Pool) :字段引用以及常量
6. 本地方法栈(Native Method Stack)
Young/new(年轻代) :分为Eden区和两个Survivor区(from和to,from:to=1:1)
Tenured/old(终身代)
Perm(永久代):非堆(Heap)内存的组成部分。主要存放加载的Class类级对象如class本身,method,field等等
Virtual: 如果-Xms 指定的值比-Xmx 的小,那么两者的差值就是Virtual内存值
内存申请过程如下:
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域
B. 当Eden空间足够时,内存申请结束。否则到下一步
C. JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收);释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区/OLD区
D. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区
E. 当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)
F. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”
OOME问题定位
1. Java.lang.OutOfMemoryError: Requested array size exceeds VM limit:分配数组内存超过VM预先分配的大小。 最新版本已没有。
2. Java.lang.OutOfMemoryError : PermGen space: 存储类对象或方法对象的永久区域溢出。可通过-XX:MaxPermSize=128m 解决。
3. Java.lang.OutOfMemoryError: JVMCI026: allocatedMemory failed : 本地内存耗尽。
4. Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) :本地内存耗尽
5. java.lang.OutOfMemoryError: Java heap space : Heap溢出。
6. java.lang.OutOfMemoryError: requested NNN bytes for MMMM. Out of swap space? : 系统交换内存用尽。
7. Java.lang.OutOfMemoryError: unable to create native thread
Java堆相关参数
-> ms/mx:定义YOUNG+OLD段的总尺寸,ms为JVM启动时YOUNG+OLD的内存大小;mx为最大可占用的YOUNG+OLD内存大小。
-> NewSize/MaxNewSize:定义YOUNG段的尺寸,NewSize为JVM启动时YOUNG的内存大小;MaxNewSize为最大可占用的YOUNG内存大小。
-> PermSize/MaxPermSize:定义Perm段的尺寸,PermSize为JVM启动时Perm的内存大小;MaxPermSize为最大可占用的Perm内存大小。
-> SurvivorRatio:设置Survivor空间和Eden空间的比例
-> -Xss参数决定Stack大小,例如-Xss1024K。如果Stack太小,也会导致Stack溢漏。 每个线程都有他自己的Stack.
备注:
1. Heap Size 最大不要超过可用物理内存的80%
2. JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。
3. 用户生产环境上一般将这两个值(最大, 最小)设为相同
4. 增加Heap Size 虽然会降低GC的频率,但也增加了每次GC的时间。
5. Heap Size 并不决定进程的内存使用量。进程的内存使用量要大
6. 假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。一般32bit来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了
调试工具
a) jmap [ option ] <pid | executable core | [server-id@]remote-hostname-or-IP>: 堆内内存使用情况, live 参数,只会打印处于生存状态的对象信息(保存虚拟机信息前强制虚拟机执行full gc)。开销很小,类似于一次full gc.
-dump:[live,]format=b,file=<filename>:以hprof二进制文件类型将虚拟机堆的信息保存到指定的文件中。
-heap:打印虚拟机堆的概要信息,堆的配置信息以及堆中各代的详细信息
-histo[:live]:打印堆中所有对象的数量、占用内存大小以及对象的完整名成。
-permstat:打印堆中永久代的类加载器的统计信息
-J-6464位的JAVA平台。
b)jhat [ options ] <heap-dump-file> jhat堆内存的dump文件,同时启动一个WEB服务器(localhost:7000/oqlhelp/)。Jhat还支持一种类似于SQL的OQL语言件所堆的dump.
c) jps [ options ] [ hostid ] jps是用于专门显示JVM进程的
d) java -agentlib:hprof/-Xrunhprof[=options] ToBeProfiledClass 性能监控的工具,堆内内存和CPU的使用进行监控和记录, 可生成文本或二进制格式保存文件
e) jstack[ option ] <pid | executable core | [server-id@]remote-hostname-or-IP>: 打印JVM线程的堆栈追踪信息,虚拟机信息
f) jinfo [ option ] pid
g) jstat工具用于显示虚拟机的性能统计信息。
h) -XX:+HeapDumpOnOutOfMemoryError: Use this JVM command line switch when launching application. Can be used with -XX:HeapDumpPath=/