在开始讲解之前,在这里先简单介绍下虚拟机启动相关的一些内存设置参数。因为OutOfMemoryError异常发生,与这些参数的设置密切相关。
举例说明含义:
-Xss128k
每个线程的java栈大小,一个线程java栈所有栈帧大小总和最大允许的尺寸128k。
-Xms128m
表示JVM Heap(堆内存)最小尺寸128MB,初始分配
-Xmx512m
表示JVM Heap(堆内存)最大允许的尺寸256MB,按需分配。
-XX:PermSize=20M
设置方法区的初始大小
-XX:MaxPermSize=30M
设置方法区的最大值
Java栈溢出
在Java虚拟机规范中,对这个区域规定了两种异常状况:StackOverflowError和OutOfMemoryError异常。
1.StackOverflowError异常
每当java程序代码启动一个新线程时,Java虚拟机都会为它分配一个Java栈。Java栈以帧为单位保存线程的运行状态。当线程调用java方法时,虚拟机压入一个新的栈帧到该线程的java栈中。只要这个方法还没有返回,它就一直存在。如果线程的方法嵌套调用层次太多(如递归调用),随着java栈中帧的逐渐增多,最终会由于该线程java栈中所有栈帧大小总和大于-Xss设置的值,而产生StackOverflowError内存溢出异常。例子如下:
-
-
-
-
public class Test {
-
-
private int count = 0;
-
-
public static void main(String[] args) {
-
new Test().method();
- }
-
-
public void method() {
- System.out.println(++count);
- method();
- }
-
- }
-Xss为128k。其中的一次测试结果为,当count的值累加到2312时,发生如下异常:
- Exception in thread "main" java.lang.StackOverflowError
-
at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:58)
-
at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:392)
-
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:447)
-
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544)
-
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:252)
-
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
-
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
-
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
-
at java.io.PrintStream.write(PrintStream.java:476)
-
at java.io.PrintStream.print(PrintStream.java:547)
-
at java.io.PrintStream.println(PrintStream.java:686)
-
at jvm.Test.method(Test.java:17)
修改-Xss为1280k。其中的一次测试结果为,当count的值累加到26888时,发生StackOverflowError异常。随着-Xss参数值的增大,可以嵌套的方法调用层次也相应增加。
综上所述,StackOverflowError异常是由于方法调用的层次太深,最终导致为某个线程分配的所有栈帧大小总和大于-Xss设置的值,从而发生StackOverflowError异常。
2.OutOfMemoryError异常
java程序代码启动一个新线程时,没有足够的内存空间为该线程分配java栈(一个线程java栈的大小由-Xss参数确定),jvm则抛出OutOfMemoryError异常。例子如下:
-
-
-
-
public class Test {
-
-
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时,发生如下异常:
- 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:640)
-
at jvm.Test.main(Test.java:20)
修改-Xss为1280k。其中的一次测试结果为,当count的值累加到1270时,发生OutOfMemoryError异常。随着-Xss参数值的增大,java程序可以创建的总线程数越少。
Java堆溢出
Java堆用于储存对象实例。当需要为对象实例分配内存,而堆的内存占用又已经达到-Xmx设置的最大值。将会抛出OutOfMemoryError异常。例子如下:
-
-
-
-
public class Test {
-
-
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时,发生如下异常:
- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
-
at java.util.Arrays.copyOf(Arrays.java:2760)
-
at java.util.Arrays.copyOf(Arrays.java:2734)
-
at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
-
at java.util.ArrayList.add(ArrayList.java:351)
-
at jvm.Test.main(Test.java:15)
修改-Xmx为10m。其中的一次测试结果为,当count的值累加到670205时,发生OutOfMemoryError异常。随着-Xmx参数值的增大,java堆中可以存储的对象也越多。
方法区溢出
方法区用于存放java类型的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。在类装载器加载class文件到内存的过程中,虚拟机会提取其中的类型信息,并将这些信息存储到方法区。当需要存储类信息而方法区的内存占用又已经达到-XX:MaxPermSize设置的最大值。将会抛出OutOfMemoryError异常。对于这种情况的测试,基本的思路是运行时产生大量的类去填满方法区,直到溢出。这里需要借助CGLib直接操作字节码运行时,生成了大量的动态类。例子如下:
-
-
-
-
public class Test {
-
-
public static void main(String[] args) {
-
int count = 0;
-
while (true) {
-
Enhancer enhancer = new Enhancer();
-
enhancer.setSuperclass(Test.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时,发生如下异常:
- Caused by: java.lang.OutOfMemoryError: PermGen space
- at java.lang.ClassLoader.defineClass1(Native Method)
-
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
-
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
-
... 8 more
修改-XX:MaxPermSize为100m。其中的一次测试结果为,当count的值累加到8022时,发生OutOfMemoryError异常。随着-XX:MaxPermSize参数值的增大,java方法区中可以存储的类型数据也越多。
相关的参考资料:
1.深入Java虚拟机(原书第2版)
2.深入理解Java虚拟机:JVM高级特性与最佳实践
3.互联网相关的文章
原文链接:http://www.cnblogs.com/evan2012/archive/2012/05/12/2497086.html
相关推荐
在 JVM 中,如果 98%的时间是用于 GC 且可用的 Heap size 不足 2%的时候将抛出内存溢出异常信息。Heap Size 最大不要超过可用物理内存的 80%,一般的要将 Xmx 和 Xms 设置相同避免每次 GC 后都要调整虚拟机堆的...
### JVM内存溢出详解 #### 一、基本概念与理解 **JVM内存溢出**是一种常见的运行时错误,指的是程序在执行过程中因为无法获得足够的内存资源而导致的问题。这种问题通常发生在程序尝试分配超出系统可用内存限制的...
### JVM实战-对象访问与内存溢出异常解析 #### 实验背景与目标 在Java虚拟机(JVM)中,不同的内存区域负责不同的功能,并且各自可能会出现特定类型的内存溢出异常。通过本实验,旨在深入理解JVM内存管理机制以及...
深入理解JVM内存区域与内存溢出异常
【JVM内存溢出】指的是Java虚拟机在运行过程中,由于内存分配不当或者内存使用过度导致内存无法正常管理,从而抛出错误的情况。这通常会导致应用程序崩溃或性能急剧下降。在Tomcat这样的Java应用服务器中,内存溢出...
JVM内存模型详解 JVM内存模型是Java虚拟机(JVM)中的一种内存管理机制,它将内存区分为永久区内存(Permanent ...通过了解JVM内存模型和对JVM的优化,可以避免内存溢出异常的发生,提高Java应用程序的性能和可靠性。
给定的部分内容中提到了一些JVM的启动参数,这些参数直接关联到内存溢出配置,下面我们来逐一解析: - **-Xms1024m**:设置JVM初始分配的堆内存大小为1024MB。这意味着JVM启动时,会立即申请1024MB的物理内存。 - *...
JAVA内存溢出问题总结 JAVA 内存溢出问题是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用的内存大于虚拟机能提供的最大内存。内存溢出问题可以从容器和程序类两个方面进行排查,容器问题...
通过对JVM堆内存溢出的分析,我们可以了解到当一个线程出现OOM异常时,它所占据的内存资源会全部被释放掉,从而不会影响其他线程的运行。 首先,让我们来了解一下JVM内存模型。JVM的内存模型主要分为五个部分:方法...
在实际开发过程中,可能会遇到以下几种内存溢出异常: 1. **`java.lang.OutOfMemoryError: Java heap space`**:这表示堆内存已满。通常,这可能是由于项目中引用了大量的jar包或其他资源导致内存使用超出预期。...
理解JVM内存结构和内存分配机制对于避免内存溢出(OutOfMemoryError)、提升程序性能、减少垃圾回收开销至关重要。开发者应关注内存配置、对象生命周期管理以及适当的垃圾回收策略,以优化应用程序的性能和稳定性。
1. **调整JVM内存设置**:增大JVM的最大堆内存大小,例如设置`-Xmx4g`表示设置最大堆内存为4GB。确保这个值不超过服务器物理内存的70%以防止操作系统因交换页面而变慢。 2. **优化Kettle步骤配置**:如问题描述中所...
虽然Python有内置的垃圾回收机制,但仍然可能出现内存泄漏和内存溢出的问题,影响程序的稳定性和效率。 **一、Python内存泄漏** 内存泄漏通常是由于以下几个原因引起的: 1. **C扩展模块的内存泄漏**:使用C语言...
Java内存溢出问题通常指的是Java应用程序在运行过程中由于内存分配不当或使用过度导致JVM无法分配更多的内存,从而抛出`java.lang.OutOfMemoryError`异常。本文将深入探讨Java内存溢出的不同类型及其解决方案。 1. ...
当系统将要发生内存溢出异常之前,会把这些软引用对象加入回收队列之中进行第二次回收。如果这次回收后还没有足够的内存,才会抛出内存溢出异常。 3. **弱引用**:弱引用与软引用相似,但它更容易被回收。只要发生...
1. **生成堆转储文件(Heap Dump)**:当Java应用程序出现内存溢出异常时,可以通过JVM参数设置(如`-XX:+HeapDumpOnOutOfMemoryError`)让JVM自动生成堆转储文件,或者通过`jmap`命令手动生成。堆转储文件是分析...
假设在生产环境中,一个项目运行三周左右会出现内存溢出异常。JDK 使用的是 64 位版本,配置参数为 `-Xmx3078M -Xms3078M -XX:PermSize=1024M -XX:MaxPermSize=1024M`。通过 MAT 分析发现: - **Histogram** 显示 ...
在JBoss运行过程中,常见的内存溢出异常包括: 1. **PermGen Space(永久代)内存溢出**:当JVM的永久代空间不足时,会抛出`java.lang.OutOfMemoryError: PermGen space`异常。 2. **Heap Space(堆空间)内存溢出*...
解决内存溢出通常涉及调整JVM参数,例如增大堆大小(`-Xms`和`-Xmx`),优化新生代和老年代的比例(`-XX:NewRatio`和`-XX:SurvivorRatio`),设置并发标记线程数(`-XX:ParallelGCThreads`)等。同时,定期分析和优化代码...