了解JVM内存结构的目的
JVM内存结构简介
-
程序计数器:当前线程所执行的字节码的行号指示器。 -
虚拟机栈:Java方法执行的内存模型,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。 -
本地方法栈:本地方法执行的内存模型,和虚拟机栈非常相似,其区别是本地方法栈为JVM使用到的Native方法服务。 -
堆:用于存储对象实例,是垃圾收集器管理的主要区域。 -
方法区:用于存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
程序计数器
虚拟机栈
/**
* VM Args: -Xss128k
*/
public class JVMStackSOF {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) {
JVMStackSOF sof = new JVMStackSOF();
try {
sof.stackLeak();
} catch (Throwable e) {
System.out.println("Stack length:" + sof.stackLength);
throw e;
}
}
}
在运行之前,设置JVM的参数为-Xss128k,运行结果如下:
Stack length:1002
Exception in thread "main" java.lang.StackOverflowError
at OneMoreStudy.JVMStackSOF.stackLeak(JVMStackSOF.java:10)
at OneMoreStudy.JVMStackSOF.stackLeak(JVMStackSOF.java:11)
at OneMoreStudy.JVMStackSOF.stackLeak(JVMStackSOF.java:11)
......
/**
* VM Args: -Xss2M
*/
public class JVMStackOOM {
private void dontStop() {
while (true) {
}
}
public void stackLeakByThread() {
while (true) {
Thread t = new Thread(new Runnable() {
public void run() {
dontStop();
}
});
t.start();
}
}
public static void main(String[] args) {
JVMStackOOM oom = new JVMStackOOM();
oom.stackLeakByThread();
}
}
Exception in thread "main" java.lang.OutMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Unknown Source)
at OneMoreStudy.JVMStackOOM.stackLeakByThread(JVMStackOOM.java:18)
at OneMoreStudy.JVMStackOOM.main(JVMStackOOM.java:24)
本地方法栈
堆
/*
* VM Args: -Xms20M -Xmx20M
*/
public class HeapOOM {
static class OOMObject{
}
public static void main(String[] args){
List list = new ArrayList();
while(true){
//把对象实例放入列表中,
//使其一直被引用,不会被垃圾回收
list.add(new OOMObject());
}
}
}
在运行之前,设置JVM的参数为-Xms20M -Xmx20M,运行结果如下:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.util.Arrays.copyOf(Unknown Source)
at java.util.ArrayList.grow(Unknown Source)
at java.util.ArrayList.ensureExplicitCapacity(Unknown Source)
at java.util.ArrayList.ensureCapacityInternal(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
at OneMoreStudy.HeapOOM.main(HeapOOM.java:18)
方法区
/*
* VM Args: -XX:PermSize=2M -XX:MaxPermSize=2M
*/
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 0; i 100000; i++) {
System.out.println(i);
//将i转化为字符串,
//并且调用intern(),把字符串放在运行时常量池
list.add(String.valueOf(i).intern());
}
}
}
......
35813
35814
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at OneMoreStudy.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:12)
......
99996
99997
99998
99999
/*
* VM Args: -XX:PermSize=2M -XX:MaxPermSize=2M
*/
public class MethodAreaOOM {
static class OOMObject {
}
public static void main(String[] args) {
for (int i = 0; i 300; i++) {
System.out.println(i);
createNewClass();
}
}
private static void createNewClass() {
//这里使用了CGLIB,动态创建类,载入方法区
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}
}
......
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
... 12 more
Exception in thread "main"
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
......
298
299
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=2M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=2M; support was removed in 8.0
总结