`
liulanghan110
  • 浏览: 1076705 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

JAVA内存错误实战

    博客分类:
  • JAVA
阅读更多

1.JAVA堆导致的内存异常

Java堆存放的是对象实例,因此只要不断建立对象,并且保证GC Roots到对象之间有可达路径即可产生OOM异常。这是由于内存泄露导致的内存溢出异常。代码如下:

package MemoryTest;

import java.util.ArrayList;
import java.util.List;

/**
 * Java堆OOM测试
 * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

 * @author zzm

 */
public class HeapOOM {

       static class OOMObject {

       }

       public static void main(String[] args) {

              List<OOMObject> list = new ArrayList<OOMObject>();
              while (true) {

                     list.add(new OOMObject());
              }
       }
}

  

 测试中限制Java堆大小为20M,不可扩展,通过参数-XX:+HeapDumpOnOutOfMemoryError让虚拟机在出现OOM异常的时候Dump出内存映像以便分析。

注:虚拟机参数设置。窗口->首选项->JAVA->已安装的JRE,在缺省的VM自变量中增加。

 

运行结果:

stack length:11347
Exception in thread "main" java.lang.StackOverflowError
	at MemoryTest.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:16)

 

 

 

 关于VM栈和本地方法栈在VM Spec描述了两种异常:StackOverflowErrorOutOfMemoryError,当栈空间无法继续分配分配时,到底是内存太小还是栈太大其实某种意义上是对同一件事情的两种描述而已.

 

1.使用-Xss参数削减栈内存容量。结果:抛出SOF异常时的堆栈深度相应缩小。

2.定义大量的本地变量,增大此方法对应帧的长度。结果:抛出SOF异常时的堆栈深度相应缩小。

3.创建几个定义很多本地变量的复杂对象,打开逃逸分析和标量替换选项,使得JIT编译器允许对象拆分后在栈中分配。结果:实际效果同第二点。

 

 

 

 

 

stack length:2402
Exception in thread "main" java.lang.StackOverflowError
	at MemoryTest.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
	at MemoryTest.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:16)

 

如果在多线程环境下,不断建立线程倒是可以产生OOM异常,但是基本上这个异常和VM栈空间够不够关系没有直接关系,甚至是给每个线程的VM栈分配的内存越多反而越容易产生这个OOM异常。

 

原因其实很好理解,操作系统分配给每个进程的内存是有限制的,譬如32Windows限制为2GJava堆和方法区的大小JVM有参数可以限制最大值,那剩余的内存为2G(操作系统限制)-Xmx(最大堆)-MaxPermSize(最大方法区),程序计数器消耗内存很小,可以忽略掉,那虚拟机进程本身耗费的内存不计算的话,剩下的内存就供每一个线程的VM栈和本地方法栈瓜分了,那自然每个线程中VM栈分配内存越多,就越容易把剩下的内存耗尽。

 

创建线程导致OOM异常

package MemoryTest;

/*
 * 创建线程导致OOM异常

 * VM Args:-Xss2M (这时候不妨设大些)

 * @author zzm

 */

public class JavaVMStackOOM {

 

       private void dontStop() {

              while (true) {

              }

       }

       public void stackLeakByThread() {

              while (true) {

                     Thread thread = new Thread(new Runnable() {

                            @Override

                            public void run() {

                                   dontStop();

                            }

                     });

                     thread.start();

              }

       }

       public static void main(String[] args) throws Throwable {

              JavaVMStackOOM oom = new JavaVMStackOOM();

              oom.stackLeakByThread();
       }
}

 

 设置好虚拟机参数后,运行上面的代码。特别提示运行上面这段代码,记得要存盘当前工作,上述代码执行时有很大令操作系统卡死的风险。结果:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread 


 

 

 

运行时常量池

 

 

要在常量池里添加内容,最简单的就是使用String.intern()这个Native方法。由于常量池分配在方法区内,我们只需要通过-XX:PermSize-XX:MaxPermSize限制方法区大小即可限制常量池容量。实现代码如下:

 

package MemoryTest;

import java.util.ArrayList;
import java.util.List;

/*
 
 * 运行时常量池导致的OOM异常
 
 * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M

 * @author zzm

 */
public class RuntimeConstantPoolOOM {

    public static void main(String[] args) {

              // 使用List保持着常量池引用,压制Full GC回收常量池行为

              List<String> list = new ArrayList<String>();

              // 10M的PermSize在integer范围内足够产生OOM了

              int i = 0; 

              while (true) {

                     list.add(String.valueOf(i++).intern());

              }

       }

}

 

设置好虚拟机参数后运行,结果如下:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
	at java.lang.String.intern(Native Method)
	at MemoryTest.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:29)

 

方法区

方法区用于存放Class相关信息,所以这个区域的测试我们借助CGLib直接操作字节码动态生成大量的Class,值得注意的是,这里我们这个例子中模拟的场景其实经常会在实际应用中出现:当前很多主流框架,如SpringHibernate对类进行增强时,都会使用到CGLib这类字节码技术,当增强的类越多,就需要越大的方法区用于保证动态生成的Class可以加载入内存。

 

package MemoryTest;
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;

/* 需要下载cglib
 
 * 借助CGLib使得方法区出现OOM异常

 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M

 * @author zzm

 */

public class JavaMethodAreaOOM {

 

       public static void main(String[] args) {

              while (true) {

                     Enhancer enhancer = new Enhancer();

                     enhancer.setSuperclass(OOMObject.class);

                     enhancer.setUseCache(false);

                     enhancer.setCallback(new MethodInterceptor(){

                            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

                                   return proxy.invokeSuper(obj, args);

                            }

                     });

                     enhancer.create();

              }

       }

 

       static class OOMObject {

       }

}

 结果:

Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)

 

本机直接内存

package MemoryTest;


import java.lang.reflect.Field;
import sun.misc.Unsafe;

/*
 
 * 本机直接内存

 * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M

 * @author zzm

 */

public class DirectMemoryOOM {

 

       private static final int _1MB = 1024 * 1024;

 

       public static void main(String[] args) throws Exception {

              Field unsafeField = Unsafe.class.getDeclaredFields()[0];

              unsafeField.setAccessible(true);

              Unsafe unsafe = (Unsafe) unsafeField.get(null);

              while (true) {

                     unsafe.allocateMemory(_1MB);

              }

       }

}

 设置好参数后运行,结果

 

Exception in thread "main" java.lang.OutOfMemoryError
	at sun.misc.Unsafe.allocateMemory(Native Method)
	at MemoryTest.DirectMemoryOOM.main(DirectMemoryOOM.java:35)

 

 

 

 2.VM栈和本地方法栈

 设置虚拟机参数后运行程序,结果如下:

分享到:
评论

相关推荐

    实战java虚拟机

    垃圾收集机制是Java内存管理的一大特色,它自动回收不再使用的对象所占用的内存,避免了程序员手动管理内存的繁琐。了解垃圾收集的工作原理和各种垃圾收集器,如Serial、Parallel、CMS和G1,对于优化程序性能至关...

    疯狂java实战演义

    了解JVM的基本工作原理对于Java开发者来说是基础,包括其内存模型、垃圾收集机制、执行引擎等。 2. 标准输入输出:文档中提到使用键盘输入来完成程序的输入部分,这涉及到Java中标准输入输出流(System.in, System....

    java内存泄露、溢出检查方法和工具

    ### Java内存泄露、溢出检查方法及工具详解 #### 一、引言 在实际的项目开发和运维过程中,经常会遇到Java应用程序出现内存溢出(`java.lang.OutOfMemoryError`)的情况。这类问题不仅影响应用程序的稳定性和性能...

    Java多线程并发实战

    #### 五、Java内存模型与管理 Java虚拟机(JVM)对内存的管理分为几个主要部分: - **堆**(Heap):用于存储所有Java对象实例的内存区域。堆的大小可以通过`-Xmx`和`-Xms`命令行选项进行调整。 - **方法区**(Method ...

    Java开发技术大全 Java开发实战经典下载地址

    4. **Java虚拟机(JVM)原理**:了解JVM的工作机制,包括内存管理、垃圾回收、类加载过程等,优化应用程序的性能。 5. **单元测试与持续集成**:掌握JUnit等测试框架的使用,实施自动化测试和持续集成,确保代码质量...

    JAVA内存调优白皮书(IBM)

    《JAVA内存调优白皮书(IBM)》是IBM公司发布的一份技术文档,主要针对Java应用程序的内存管理和性能优化提供了深入的指导。在Java世界中,内存管理是决定程序性能、稳定性和可扩展性的重要因素,特别是Java虚拟机...

    《Java编程实战宝典》原版图书配套ppt

    10. **JVM内存管理**:Java的垃圾收集器是自动内存管理的关键,PPT会讲解堆内存、栈内存以及垃圾回收机制。 11. **设计模式**:作为软件开发的良好实践,设计模式如单例、工厂、观察者等会在PPT中得到详细解读,...

    Java 并发编程实战

    此外,书中还详细讲解了Java内存模型(JMM),这是理解多线程间数据同步和可见性的重要理论基础。 接着,书中深入探讨了Java并发库的使用,如java.util.concurrent包下的ExecutorService、Future、Callable接口,...

    Java开发实战经典(名师讲坛)].李兴华.pdf

    3. **异常处理**:Java通过异常处理机制来处理运行时错误,通过try-catch-finally语句块捕获和处理异常,以确保程序的健壮性。书中会详细讲解如何正确使用异常处理来编写稳定代码。 4. **IO与NIO**:Java的输入/...

    java+大数据项目实战.zip

    10. **最佳实践**:项目实战提供了应用最佳编程和大数据处理实践的机会,例如模块化设计、代码复用、错误处理等。 总之,这个压缩包中的项目实战涵盖了Java编程和大数据处理的多个方面,是理论学习与实际操作相结合...

    JAVA开发实战经典(源代码).

    10. **异常处理**:Java异常处理是程序错误处理的重要手段。通过理解异常的层次结构、如何抛出和捕获异常,可以编写健壮的程序。 以上知识点都是《JAVA开发实战经典》一书可能涉及的内容,通过源代码的学习和实践,...

    java+大数据相关框架实战项目(Hadoop, Spark, Storm, Flink).zip

    在实战项目中,你将有机会深入理解这些框架的工作原理,学习如何利用Java API进行数据读写、数据转换、作业提交和错误处理等。每个框架都有其特定的应用场景和优缺点,比如Hadoop适合离线批处理,Spark适用于交互式...

    JAVA并发编程实践.pdf+高清版+目录 书籍源码

    其次,书中深入剖析了Java内存模型(JMM)和可见性问题,这是理解并发编程中数据一致性问题的基础。Java的volatile关键字、synchronized块和方法、以及Atomic类都是解决这些问题的关键工具。作者通过实际案例解释了...

    Java并发编程实战

    《Java并发编程实战》这本书是Java开发者深入理解并发编程的重要参考资料。书中的内容涵盖了Java并发编程的各个方面,包括基础概念、线程管理、同步机制、并发工具类以及高性能并发设计模式等。以下是对这些知识点的...

    java内存分配 .pdf

    ### Java内存分配详解 #### 一、Java内存区域与内存溢出异常 Java虚拟机(JVM)在运行过程中会管理多种不同的内存区域,这些区域各自承担着特定的任务,并且每种区域都有可能发生内存溢出异常。 ##### 1.1 程序...

    47-Java性能调优实战.zip

    本实战课程聚焦于提升Java程序的性能,涵盖了多个关键领域,包括Java编程、JVM性能监测与调优、多线程性能优化以及数据库性能优化等。 首先,模块一概述部分可能介绍了性能调优的基本概念和重要性,以及Java性能...

    Java软件开发实战 Java基础与案例开发详解 1-1 什么是java 共8页.pdf

    ### Java软件开发实战知识点梳理 #### 1-1 什么是Java - **计算机编程语言**:Java是一种面向对象的编程语言。 - **软件开发平台**:提供了完整的开发环境,包括编译器、解释器和一系列工具。 - **软件运行平台**:...

    Java高级程序设计实战教程-源代码.rar

    Java高级程序设计实战教程是深入理解并提升Java编程技能的重要资源。这个压缩包"Java高级程序设计实战教程-源代码.rar"很可能包含了丰富的实例代码,旨在帮助学习者通过实践来掌握高级Java编程概念。标签“教学资料...

    Java开发实战经典(李兴华老师)

    理解内存模型、垃圾回收机制以及如何分析和优化性能,是提升Java应用效率的关键。笔记中可能包含JVM参数调整实例和性能监控工具的使用方法。 最后,Spring框架的使用是企业级Java开发的常见实践。Spring的依赖注入...

    Java软件开发实战 Java基础与案例开发详解 1-2 认识java语言 共10页.pdf

    ### Java软件开发实战:Java基础与案例开发详解 #### 1-2 认识Java语言 **1.2.1 Java语言的特性** Java是一种功能强大且用途广泛的编程语言,其核心特性包括: 1. **简单高效**:Java语言的设计理念之一就是简单...

Global site tag (gtag.js) - Google Analytics