`

Java虚拟机(1)自动内存管理机制

 
阅读更多
Java内存区域与内存溢出异常

一、概要

我们可以带着以下几个问题去学习自动内存管理机制,罗列如下:

  1. 什么操作可能导致内存溢出?
  2. 有哪些种类的内存溢出?
  3. 都是在内存的哪些区域溢出?
  4. 垃圾收集有哪些原则?
  5. 有哪些垃圾收集算法及其实现?
  6. 新生代和老年代的回收策略如何?
  7. 各种内存相关的JVM参数是什么意思?

本文章主要总结问题1、问题2和问题3


二、运行时数据区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,如下图所示


其中虚拟机栈、本地方法栈和程序技术器是线程私有的,方法区和堆是线程共享的.

2.1程序计数器

作用:当前线程所执行的字节码的行号指示器

  • 字节码解释器工作时通过改变它的值来选取下一条需要执行的字节码指令
  • 分支、循环、跳转、异常处理和线程恢复都依赖于它

2.2虚拟机栈

栈的作用:栈用于存储局部变量表、操作数栈、动态链接和方法出口等信息.

其中局部变量表用于存放8种基本数据类型(boolean,byte,char,short,int,float,long,double)和reference类型.

reference类型:

  • 指向对象起始地址的引用指针

  • 指向一个代表对象的句柄

  • 指向一条字节码指令的地址

可抛出两种异常状况

  • 线程请求的栈深度大于虚拟机所允许的栈深度,抛出StackOverflowError异常

  • 当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常

2.3本地方法栈

与虚拟机栈的作用非常相似.其区别是虚拟机栈执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务

同时也会抛出StackOverflowError和OutOfMemoryError异常

2.4堆

堆的作用:分配所有的对象实例和数组。可以抛出OutOfMemoryError异常。

2.5方法区

方法区的作用:用于存储已被虚拟机加载的类信息(Class)、常量(final修饰)、静态变量(static)和即时编译器编译后的代码(code)

可以抛出OutOfMemoryError异常

2.6运行时常量池

属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用(在以后介绍Class结构会讲到),在类加载后存放到方法区的运行时常量池中。可抛出OutOfMemoryError异常

三、对象访问

主流的两种访问方式:使用句柄和直接指针。(HotSpot虚拟机就是使用直接指针的访问方式)

使用句柄访问


使用直接指针访问


优缺点比较


四、OutOfMemoryError异常

在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能.

下面通过若干实例来验证异常发生的场景.以下代码的开头都注释了执行时所需要设置的虚拟机启动参数,这些参数对实验结果有直接影响,请调试代码的时候不要忽略掉.

4.1Java堆溢出

堆里放的是new出来的对象,所以这部分很简单不断的new对象就可以了,但是为了防止对象new出来之后被GC,所以把对象new出来的对象放到一个List中去即可。为了有更好的效果,可以在运行前,调整堆的参数。

import java.util.ArrayList;

import java.util.List;

/**

 * VM Args: -Xms20m -Xms20m - XX:+HeapDumpOnOutOfMemoryError

 * @author Administrator

 *

 */

public class HeapOOM {

       static class OOMObject{}

       public static void main(String[] args) {

            List<OOMObject> list = new ArrayList<HeapOOM.OOMObject>();

             while(true ){

                  list.add( new OOMObject());

            }

      }

}


运行结果

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid3688.hprof ...
Heap dump file created [364376345 bytes in 15.891 secs]

4.2虚拟机栈溢出

  • 在单线程的堆中我们不断的让一个成员变量自增,容纳这个变量的单元无法承受这个变量了,就抛出StackOverflowError了。
  • 可以开尽量多的线程,并在每个线程里调用native的方法,就自然会抛出OutOfMemoryError了
/**

 * VM Args: - Xss64k

 * @author Administrator

 *

 */

public class JavaVMStackSOF {

       private int stackLength = 1;

       public void stackLeak(){

             stackLength ++;

            stackLeak();

      }

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

            JavaVMStackSOF oom = new JavaVMStackSOF();

             try{

                  oom.stackLeak();

            } catch(Throwable e){

                  System. out.println("Stack length:" + oom.stackLength);

                   throw e;

            }

      }

}


运行结果
Stack length:914        

Exception in thread "main" java.lang.StackOverflowError        

      at JavaVMStackSOF.stackLeak(                   JavaVMStackSOF.java:9         )        

      at JavaVMStackSOF.stackLeak(                   JavaVMStackSOF.java:10         )        

      at JavaVMStackSOF.stackLeak(                   JavaVMStackSOF.java:10         )        



4.3 方法区溢出

可采用增强Class加载的方式。基本思路是运行时产生大量的类去填满方法区,直到溢出。
借助第三方类库CGLib 直接操作字节码运行,生成大量的动态类。
import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodProxy;

/**

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

 * @author Administrator

 *

 */

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() {

                         @Override

                         public Object intercept(Object obj, Method method, Object[] args,

                                    MethodProxy proxy) throws Throwable {

                               return proxy.invoke(obj, args);

                        }

                  });

                  enhancer.create();

            }

      }

       static class OOMObject{

             

      }

}


运行结果
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

4.4 运行时常量池溢出

可采用String类的intern方法。
import java.util.ArrayList;

import java.util.List;

/**

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

 * @author Administrator

 *

 */

public class RuntimeConstantPoolOOM {

       public static void main(String[] args) {

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

             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 RuntimeConstantPoolOOM.main( RuntimeConstantPoolOOM.java:14 )

五、小结

主要介绍虚拟机里面的内存是如何划分的,哪部分区域、什么样的代码和操作可能导致内存溢出异常。

分享到:
评论

相关推荐

    Java虚拟机中内存管理机制.pdf

    Java虚拟机(JVM)的内存管理机制是Java编程中至关重要的部分,它涉及到程序的性能和稳定性。本文主要分析了Java虚拟机的内存管理,特别是垃圾回收机制及其实现。 首先,Java虚拟机中的内存主要分为堆内存和栈内存...

    Java虚拟机内存管理总结

    Java虚拟机内存管理总结 Java虚拟机(JVM)中的内存管理是指Java语言中对象的分配和释放问题。Java中的内存管理可以分为两部分:对象的分配和释放。 对象的分配是由程序完成的,程序员需要通过关键字new为每个对象...

    JAVA虚拟机的内存管理

    本文档旨在对Sun J2SE 5.0版本中的Java HotSpot虚拟机(JVM)内存管理机制进行全面概述,包括不同类型的内存收集器及其配置方法、如何调整收集器内存区域的大小等。此外,还将提供一些影响内存收集器行为的常见选项,...

    深入理解Java 虚拟机内存模型.rar

    - **垃圾收集(Garbage Collection, GC)**:自动内存管理,清理不再使用的对象,防止内存泄漏。包括新生代GC(Minor GC)、老年代GC(Major GC)和全GC(Full GC)。 - **内存溢出与内存泄漏**:当内存耗尽或无法...

    Java的内存管理机制分析

    - 堆内存是所有线程共享的,由Java虚拟机自动管理。 - 堆内存的大小可以通过JVM参数来设置,如`-Xms`和`-Xmx`来指定初始大小和最大限制。 3. **数据段(Data Segment)**: - 包括静态域和常量池两部分。 - **...

    Java虚拟机规范中文版.pdf

    例如,对JVM的垃圾回收算法的了解,有助于开发者编写出更适合自动内存管理的代码。了解JVM的线程模型,有助于编写高性能的多线程程序。 JVM规范是不断发展的,随着Java技术的发展,它也在不断地进行改进和扩展。...

    java虚拟机

    3. **垃圾收集与内存管理**:JVM负责自动管理内存,包括对象的分配和回收。垃圾收集器是其重要组成部分,通过标记-清除、复制、标记-整理和分代收集等多种算法来释放不再使用的内存。 4. **类加载过程**:类的生命...

    Java虚拟机(Java VM) msjavax86 微软java虚拟机

    垃圾收集自动管理内存,避免程序员手动处理内存泄露问题;JIT编译则是在运行过程中将频繁执行的热点代码编译成本地机器码,提升运行效率。 总的来说,Java虚拟机是Java生态系统中的关键组件,它使得Java程序能够在...

    java虚拟机各种版本

    此外,JVM还实现了垃圾回收机制,自动管理内存,避免了程序员手动管理内存的麻烦。 JVM还有许多优化技术,如分代垃圾收集、并行/并发GC、压缩引用、逃逸分析等,这些都对提升Java应用的性能起到了关键作用。对于...

    深入java虚拟机 高清pdf 高清高清高清

    3. **垃圾收集与内存管理**:Java虚拟机中的垃圾收集机制是自动进行内存管理的关键。书里介绍了不同的垃圾收集算法(如标记-清除、复制、标记-整理、分代收集等)以及垃圾收集器(如Serial、ParNew、CMS、G1等),...

    JAVA虚拟机内存分配与回收机制[文].pdf

    JAVA虚拟机的内存分配与回收机制是JAVA语言的核心机制之一,栈和堆是JAVA用于在RAM中存放数据的地方,JAVA自动管理栈和堆,程序员不能直接地设置栈或堆。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小...

    JAVA虚拟机内存分配机制

    JAVA虚拟机内存分配机制是Java程序执行过程中内存管理的核心部分,它涉及到程序的性能和效率。Java虚拟机(JVM)内存主要分为两大部分:栈内存和堆内存。 栈内存主要存储程序运行过程中的局部变量,包括基本类型...

    安卓的JAVA虚拟机 简单实用

    同时,ART也提供了垃圾回收和内存管理机制,有助于提高应用的稳定性和效率。 3. **JAVA虚拟机的执行过程** 在Android中,Java源代码首先通过编译器生成.class文件,然后通过dx工具转换为.dex文件。在设备上,ART会...

    深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理).zip

    此外,JVM的垃圾收集机制是其内存管理的关键,它自动回收不再使用的对象,避免内存泄漏。 为了更好地理解和分析JVM行为,开发者通常会借助各种工具,如VisualVM、JProfiler和JConsole等。这些工具可以实时监控JVM的...

    Java运行原理与Java虚拟机.pdf

    2. **内存保护**:通过内存管理机制,JVM可以防止程序访问非法内存区域,避免内存泄漏和其他内存相关的问题。 3. **数据流分析**:字节码验证器会进行数据流分析,确保所有变量在使用前已经被正确初始化。 4. **...

    Java虚拟机规范 深入java虚拟机

    它详细阐述了Java虚拟机(JVM)的工作原理,包括内存管理、类加载机制、字节码执行以及垃圾回收等核心概念。深入理解这些知识点对于提升程序性能、解决运行时问题以及设计高效的应用程序至关重要。 1. **JVM架构** ...

    JAVA虚拟机解读入门

    4. 内存管理:主要涉及垃圾收集机制,自动回收不再使用的对象,避免内存泄漏。现代JVM使用多种垃圾收集算法,如标记-清除、复制、标记-整理和分代收集等。 5. 本地方法接口:允许JVM调用原生的C/C++代码,实现与...

    Java虚拟机解释执行机制研究.pdf

    Java语言丰富的类库支持、自动内存管理和跨平台执行能力是其显著的优势,使得Java语言在互联网、企业网和嵌入式设备等领域广泛应用。JVM通过其解释执行机制和即时编译技术,使得Java程序具备了良好的平台无关性和...

Global site tag (gtag.js) - Google Analytics