Java堆中存放Object对象数据,例如new出来的Object。当没有任何引用指向某对象时,该对象可能被垃圾回收。有关垃圾回收算法,可参考其他有关文章,网上很多。关于对象引用,按强弱还有强引用,软引用,弱引用,虚引用之分。强引用,一般不会被垃圾回收,若内存不足,只好抛出OutOfMemoryError;软引用,垃圾回收器扫描时,若是内存不足的情况下,这种引用的对象会被回收。弱引用,只要垃圾回收器扫描,就会回收。

栈是动态的,每起一个线程就会起一个栈,每个线程中每个方法会在栈中起一个帧,称栈帧;每一帧中存的是方法的局部变量,中间值等信息。方法执行结束,栈帧内存释放,线程结束栈内存释放。

在Java虚拟机规范的描述中,除了PC(程序计数器)寄存器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能。当发生OutOfMemoryError异常时,无法用try...catch捕捉。

在开始讲解之前,在这里先简单介绍下虚拟机启动相关的一些内存设置参数。因为OutOfMemoryError异常发生,与这些参数的设置密切相关。

-Xss128k

每个线程的java栈大小,一个线程java栈所有栈帧大小总和不能超过128k。

-Xms128m

表示JVM Heap(堆内存),初始分配128MB

-Xmx512m

表示JVM Heap(堆内存)最大允许的尺寸512MB。

-XX:PermSize=20M

设置方法区的初始大小

-XX:MaxPermSize=30M

设置方法区的最大值

Java栈溢出

在Java虚拟机规范中,对这个区域规定了两种异常状况:StackOverflowError和OutOfMemoryError异常。

1.StackOverflowError异常

每当java程序代码启动一个新线程时,Java虚拟机都会为它分配一个Java栈。Java栈以帧为单位保存线程的运行状态。当线程调用java 方法时,虚拟机压入一个新的栈帧到该线程的java栈中。只要这个方法还没有返回,它就一直存在。如果线程的方法嵌套调用层次太多(如递归调用),随着 java栈中帧的逐渐增多,最终会由于该线程java栈中所有栈帧大小总和大于-Xss设置的值,而产生StackOverflowError内存溢出异 常。例子如下:

package leon.java.outofmemory;

public class StackOverflow {
private static int count = 0; public static void main(String[] args) {
method();
} public static void method() {
System.out.println(++count);
method();
} }

-Xss为128k。其中的一次测试结果为,当count的值累加到2312时,发生如下异常:

  1. Exception in thread "main" java.lang.StackOverflowError
  2. at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:58)
  3. at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:392)
  4. at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:447)
  5. at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544)
  6. at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:252)
  7. at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
  8. at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
  9. at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
  10. at java.io.PrintStream.write(PrintStream.java:476)
  11. at java.io.PrintStream.print(PrintStream.java:547)
  12. at java.io.PrintStream.println(PrintStream.java:686)
  13. at jvm.Test.method(Test.java:17)

修改-Xss为1280k。其中的一次测试结果为,当count的值累加到26888时,发生StackOverflowError异常。随着-Xss参数值的增大,可以嵌套的方法调用层次也相应增加。

综上所述,StackOverflowError异常是由于方法调用的层次太深,最终导致为某个线程分配的所有栈帧大小总和大于-Xss设置的值,从而发生StackOverflowError异常。

2.OutOfMemoryError异常

java程序代码启动一个新线程时,没有足够的内存空间为该线程分配java栈(一个线程java栈的大小由-Xss参数确定),jvm则抛出OutOfMemoryError异常。例子如下:

package leon.java.outofmemory;

public class OutoffMemory {

    public static void main(String[] args) {
int count = 0;
while (true) {
Thread thread = new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(5000);
} catch (Exception e) { }
}
}
});
thread.start();
System.out.println(++count);
}
}
}

-Xss为128k。其中的一次测试结果为,当count的值累加到11887时,发生如下异常:

  1. Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
  2. at java.lang.Thread.start0(Native Method)
  3. at java.lang.Thread.start(Thread.java:640)
  4. at jvm.Test.main(Test.java:20)

修改-Xss为1280k。其中的一次测试结果为,当count的值累加到1270时,发生OutOfMemoryError异常。随着-Xss参数值的增大,java程序可以创建的总线程数越少。

Java堆溢出

Java堆用于储存对象实例。当需要为对象实例分配内存,而堆的内存占用又已经达到-Xmx设置的最大值。将会抛出OutOfMemoryError异常。例子如下:

package leon.java.outofmemory;

import java.util.ArrayList;
import java.util.List; public class HeapOutoffMemory { public static void main(String[] args) {
int count = 0;
List<Object> list = new ArrayList<Object>();
while (true) {
list.add(new Object());
System.out.println(++count);
}
}
}

-Xmx为5m。其中的一次测试结果为,当count的值累加到297868时,发生如下异常:

  1. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  2. at java.util.Arrays.copyOf(Arrays.java:2760)
  3. at java.util.Arrays.copyOf(Arrays.java:2734)
  4. at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
  5. at java.util.ArrayList.add(ArrayList.java:351)
  6. at jvm.Test.main(Test.java:15)

修改-Xmx为10m。其中的一次测试结果为,当count的值累加到670205时,发生OutOfMemoryError异常。随着-Xmx参数值的增大,java堆中可以存储的对象也越多。

方法区溢出

方法区用于存放java类型的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。在类装载器加载class文件到内存的过程中,虚拟机 会提取其中的类型信息,并将这些信息存储到方法区。当需要存储类信息而方法区的内存占用又已经达到-XX:MaxPermSize设置的最大值。将会抛出 OutOfMemoryError异常。对于这种情况的测试,基本的思路是运行时产生大量的类去填满方法区,直到溢出。这里需要借助CGLib直接操作字 节码运行时,生成了大量的动态类。例子如下:

package leon.java.outofmemory;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; public class MaxPermSizeOverflow {
public static void main(String[] args) {
int count = 0;
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MaxPermSizeOverflow.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invoke(obj, args);
}
});
enhancer.create();
System.out.println(++count);
}
}
}

-XX:MaxPermSize为50m。其中的一次测试结果为,当count的值累加到3953时,发生如下异常:

  1. Caused by: java.lang.OutOfMemoryError: PermGen space
  2. at java.lang.ClassLoader.defineClass1(Native Method)
  3. at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
  4. at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
  5. ... 8 more

修改-XX:MaxPermSize为100m。其中的一次测试结果为,当count的值累加到8022时,发生OutOfMemoryError异常。随着-XX:MaxPermSize参数值的增大,java方法区中可以存储的类型数据也越多。

JVM的参数设置与OutOfMemoryError异常关系的更多相关文章

  1. jvm常用参数设置 专题

    在jdk8中 -Xms2g不合法,能通过的:-Xms2G #!/bin/bash JAVA_OPTS="-Xms4G -Xmx4G -XX:+HeapDumpOnOutOfMemoryErr ...

  2. jvm常用参数设置 good

    1.堆的大小可以通过 -Xms 和 -Xmx 来设置,一般将他们设置为相同的大小,目的是避免在每次垃圾回收后重新调整堆的大小,比如 -Xms=2g -Xmx=2g 或者 -Xms=512m -Xmx= ...

  3. 了解java虚拟机—JVM相关参数设置(2)

    1.   JVM相关参数设置 JVM相关配置 -XX:+PrintGC 两次次YoungGC,两次FullGC. -XX:+PrintGCDetails 打印GC时的内存,并且在程序结束时打印堆内存使 ...

  4. JVM常用参数设置

    堆内存设置 示例: java -Xmx4550m -Xms4550m -Xss128k -XX:NewRatio=5 -XX:SurvivorRatio=5 -Xmx4550m:设置JVM最大可用内存 ...

  5. 深入理解java虚拟机笔记补充-JVM常见参数设置

    JVM 常见参数设置 内存设置 参数 -Xms:初始堆大小,JVM 启动的时候,给定堆空间大小. -Xmx:最大堆大小,如果初始堆空间不足的时候,最大可以扩展到多少. -Xmn:设置年轻代大小.整个堆 ...

  6. HotSpot JVM常用参数设置

    转自:https://www.zybuluo.com/jewes/note/57352 选项的分类 Hotspot JVM提供以下三大类选项: 1. 标准选项:这类选项的功能是很稳定的,在后续版本中也 ...

  7. JVM相关参数设置

    Java启动参数共分为三类: 其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容: 其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足, ...

  8. tomcat端口修改以及jvm启动参数设置

    1.端口更改:找到config目录下server.xml文件 如下 <?xml version='1.0' encoding='utf-8'?> <!-- Licensed to t ...

  9. jvm 启动参数设置(转载)

    JVM启动参数 http://onlyor.iteye.com/blog/1722413 博客分类: java java java启动参数共分为三类其一是标准参数(-),所有的JVM实现都必须实现这些 ...

随机推荐

  1. 开博第一篇:DHT 爬虫的学习记录

    经过一段时间的研究和学习,大致了解了DHT网络的一些信息,大部分还是参会别人的相关代码,一方面主要对DHT爬虫原理感兴趣,最主要的是为了学习python,大部分是别人的东西原理还是引用别人的吧 DHT ...

  2. 再次学习C++类之构造函数

    学习C++类,首先要说C中的结构体,虽然C++类扩展了C中的结构体,可以添加成员函数,但他们是有区别的.在结构体中,成员变量.成员函数都是公有的,而类中,一般是成员变量是私有的,成员函数是公有的,私有 ...

  3. win32进程间通讯--共享内存

    小白一枚,如有不对,请各位大神多多指教! 最近看了看win32进程间通讯.简单写了写利用共享内存实现进程间通讯 使用共享内存实现进程间通讯: 1.在WM_CREATE消息下创建文件映射内核对象 hMa ...

  4. Foreign Exchange

     10763 Foreign ExchangeYour non-profit organization (iCORE - international Confederation of Revolver ...

  5. 十、mysql事务的简介

    1. myisam跟memory支持表级别锁定 BDB 页级锁定 Innodb 行级锁定 2.表锁(不是表嫂哈) lock table read //只读表锁,也就是说执行了这个锁后,锁内的操作只能为 ...

  6. 【IOS】利用ASIHTTPRequest 实现一个简单的登陆验证

    http://blog.csdn.net/toss156/article/details/7638529

  7. Code for the Homework1

    作业要求: http://www.cnblogs.com/bingc/p/4919692.html 代码(未使用Eigen): #include <iostream> #include & ...

  8. 如何把由js生成的内容水平居中?

    一.问题来源 如右侧的微博关注组件,直接用div的align居中没效果,我就开始百度了.即在<div> <script>.....</script>  </d ...

  9. hdu 4662

    将U全部转化为I   因为 I 的个数一定是2的n次方  有可能消除了一定数量的 2U  所以I的个数加上一个6的整数倍是2的n次方 #include <iostream> #includ ...

  10. uva 825

    这个......小学生就会的  坑在输入输出了  两个数之间可能不止一个空格....wa了好几遍啊 #include <cstdio> #include <cstring> # ...