JVM执行Java程序的过程中管理的内存空间包括下列几个区域 程序计数器(Program CounterRegister) · 线程私有占用空间很小 · 线程所执行代码行号指示器 · 解释器通过计数器的值选择下一条执行的字节码指令 · 线程执行Native方法时值为空 · 没有OOM(OutOfMemory)Java虚拟机栈(Java Virtual Machine Stacks) · 线程私有· 储存方法栈帧(Stack Frame) · 栈帧储存局部变量表操作栈动态链接方法出口等 · 局部变量表编译器可知的基本类型对象引用和returnAddress(字节码指令的地址)在编译期间完成分配运行时大小不变 · 存在StackOverflowError和OOM · StackOverflowError线程请求栈深度大于VM允许深度 · OOM创建线程或扩展线程空间时无足够内存 StackOverflowError例子 /** * Xssk * * @author Alfred Xu <> * */ public class StackSOF { int recursionLength; void recusion() { recursionLength++; recusion(); } public static void main(String[] args) { StackSOF sof = new StackSOF(); try { sofrecusion(); } catch (Throwable e) { Systemoutprintln(sofrecursionLength); eprintStackTrace(); } } } OOM例子 /** * Xssm * * @author Alfred Xu <> * */ public class StackOOM { static class Tester extends Thread { @Override public void run() { try { Threadsleep( * ); } catch (InterruptedException e) { eprintStackTrace(); } } } public static void main(String[] args) { for (int i = ;; i++) { new Tester()start(); Systemoutprintln(i); } } } 本地方法栈(Native MethodStacks) · 线程私有类似虚拟机栈 · 服务Native方法 · 同样存在StackOverflowError和OOM · Hotspot中将Java虚拟机栈和本地方法栈合二为一通过Xss设置大小JDK以前默认K默认M Java堆(Java Heap) · 所有线程共享 · 储存对象实例 · GC和OOM的主要区域 Heap OOM例子 /** * Xmsm Xmxm * * @author Alfred Xu <> * */ public class HeapOOM { public static void main(String[] args) { List<Long> list = new ArrayList<Long>(); for (long i = ;; i++) { listadd(i); Systemoutprintln(i); } } } 方法区(Method Area) · 又叫非堆(NonHeap)对应HotSpot的永久代(Permanent Generation) · 所有线程共享 · 储存VM加载的类信息常量静态变量JIT编译代码等 · 也有OOM一般是由于大量使用反射生成class · 包含运行时常量池(Rumtime ConstantPool) 常量池溢出例子 /** * XX:MaxPermSize=m * * @author Alfred Xu <> * */ public class ConstantPoolOOM { public static void main(String[] args) { List<String> list = new ArrayList<String>(); for (int i = ;; i++) { listadd(StringvalueOf(i)intern()); Systemoutprintln(i); } } } 本机直接内存(Direct Memory) · 不受VM直接管理但也有OOM · 和NIO中的DirectByteBuffer相关 · 默认和Java堆大小一致 例子 /** * XX:MaxDirectMemorySize=m * * @author Alfred Xu <> * */ @SuppressWarnings(restriction) public class DirectMemoryOOM { static final int _MB = * ; static void unsafeAllocate() throws IllegalArgumentException IllegalAccessException { Field unsafeField = UnsafeclassgetDeclaredFields()[]; unsafeFieldsetAccessible(true); Unsafe unsafe = (Unsafe) unsafeFieldget(null); List<Long> list = new ArrayList<Long>(); for (int i = ;; i++) { long l = unsafeallocateMemory(_MB); listadd(l); Systemoutprintln(i); } } static void byteBufferAllocate(boolean direct) { List<ByteBuffer> list = new ArrayList<ByteBuffer>(); for (int i = ;; i++) { ByteBuffer bb; if (direct) { bb = ByteBufferallocateDirect(_MB); } else { bb = ByteBufferallocate(_MB); } listadd(bb); Systemoutprintln(i); } } public static void main(String[] args) throws IllegalArgumentException IllegalAccessException { byteBufferAllocate(true); // unsafeAllocate(); } } Hotspot Java内存空间结构 新生代(Young Generation) 大部分的对象的内存分配和回收在这里完成 Eden 新建的对象分配在此minor GC后被清空 Survivor 存储至少经过一次GC存活下来的对象以增大该对象在提升至老生代前被回收的机会 From Space 在minor GC后被清空GC后存活的对象放入老生代 To Space Eden中在新生代GC后存活的对象放在此 老生代(Old Generation) 多次GC后存活的对象或者新生代放置不下的大对象 永生代(PermanentGeneration) 方法区 |