说明:本篇博客属于读书笔记,大量参考《深入理解Java虚拟机》这本书
public class DemoMain {
public static void main(String[] args) {
System.out.println("test");
DemoMain.testMethod();
System.out.println("end");
}
public static void testMethod() {
testMethod();
}
}
如上的应用程序运行之后,在我的机器上会抛出StackOverflowError:
test
Exception in thread "main" java.lang.StackOverflowError
at com.lhd.jvmdemo1.DemoMain.testMethod(DemoMain.java:12)
at com.lhd.jvmdemo1.DemoMain.testMethod(DemoMain.java:12)
at com.lhd.jvmdemo1.DemoMain.testMethod(DemoMain.java:12)
at com.lhd.jvmdemo1.DemoMain.testMethod(DemoMain.java:12)
at com.lhd.jvmdemo1.DemoMain.testMethod(DemoMain.java:12)
at com.lhd.jvmdemo1.DemoMain.testMethod(DemoMain.java:12)
at com.lhd.jvmdemo1.DemoMain.testMethod(DemoMain.java:12)
当虚拟机在执行方法testMethod的时候,这时候就会在Java虚拟机栈上创建一个栈帧,然后入栈,然而在testMethod方法内又不断的递归调用testMethod方法,导致Java虚拟机栈不断的嵌套执行testMethod方法,不断的创建testMethod的栈帧,然后入栈,而testMethod并没有执行完成,所以testMethod对应的栈帧不会出栈,当Java虚拟机栈中的栈深度超过了虚拟机允许的深度,这时候就抛出了StackOverflowError异常了,如果虚拟机可以动态拓展,在新的栈帧入栈的时候再去申请内存,要是申请不到足够的内存,此时就会抛出OOM异常了
Object obj = new Object();
obj是对象的引用,存储在Java虚拟机栈中,而new出来的Object对象实例就存储在Java堆中,obj引用指向Java堆中实例的地址,Java堆是垃圾回收管理的主要区域,Java堆的内存空间不需要物理上的连续,只需要逻辑上的连续即可,Java堆也会抛出StackOverflowError 和OOM异常
public class DemoMain {
public static void main(String[] args) {
System.out.println("test");
String s1 = "s1";
String s2 = "s1";
String s3 = new String("s1");
System.out.println(s1 == s2);
System.out.println("end");
}
}
以上运行的结果是:
test
true
end
也就是说是s1指向的地址和s2指向的地址是一样的,为什么?因为“s1”这个字符串常量被存储到了字符串常量池中了,虚拟机发现了s1对象指向“s1”,s2对象也指向“s1”,因此不会再次创建一个“s1”,而是将s1和s2对象都指向存储于常量址的“s1”,这里就做到了常量池的对象共享,节省内存
image.png
public static void main(String[] args) {
List list = new ArrayList();
while (true) {
list.add(new Object());
}
}
不断的分配对象,并添加到list当中,这样对象就不会被回收,程序跑一会儿就报Java堆的OOM异常:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
什么情况可能会导致Java堆的内存泄漏?很明显,内存泄漏,一些对象创建后,一直被持有导致GCRoot一直存在,所以不会被回收
public class DemoMain {
int i = 0;
public static void main(String[] args) {
DemoMain demoMain = new DemoMain();
try {
demoMain.test();
} catch (Throwable e) {
System.err.println("stack:" + demoMain.i);
e.printStackTrace();
}
}
public void test() {
i++;
test();
}
}
运行结果:
stack:34879
java.lang.StackOverflowError
at com.lhd.jvmdemo1.DemoMain.test(DemoMain.java:22)
at com.lhd.jvmdemo1.DemoMain.test(DemoMain.java:22)
at com.lhd.jvmdemo1.DemoMain.test(DemoMain.java:22)
at com.lhd.jvmdemo1.DemoMain.test(DemoMain.java:22)
at com.lhd.jvmdemo1.DemoMain.test(DemoMain.java:22)
at com.lhd.jvmdemo1.DemoMain.test(DemoMain.java:22)
at com.lhd.jvmdemo1.DemoMain.test(DemoMain.java:22)
public class DemoMain {
public static void main(String[] args) {
DemoMain demoMain = new DemoMain();
demoMain.createThread();
}
public void createThread() {
while (true) {
new Thread(){
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:714)
at com.lhd.jvmdemo1.DemoMain.createThread(DemoMain.java:26)
at com.lhd.jvmdemo1.DemoMain.main(DemoMain.java:12)
这个是本地方法区抛出的OOM异常
java.lang.OutOfMemoryError:PermGen space
在android开发中,如果一个apk的类非常多,安装这个apk的时候就可能出现方法区的内存不够用导致方法区内存溢出