首页 >Java >java教程 >Java内存管理和内存溢出异常的详解

Java内存管理和内存溢出异常的详解

黄舟
黄舟原创
2017-10-18 09:35:421695浏览

下面小编就为大家带来一篇浅谈java内存管理与内存溢出异常。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

说到内存管理,笔者这里想先比较一下java与C、C++之间的区别:

在C、C++中,内存管理是由程序员负责的,也就是说程序员既要完成繁重的代码编写工作又要时常考虑到系统内存的维护

在java中,程序员无需考虑内存的控制和维护,而是交由JVM自动管理,这样就不容易出现内存泄漏和溢出的问题。然而,一旦出现内存泄漏和溢出方面的问题,如果不了解JVM的内存管理机制就很难找到错误所在。

1.JVM运行时数据区

JVM在运行java程序的时候会将它所管理的内存划分为若干个不同的区域,这些区域不仅有自己的用途,还有创建和销毁的时间。一般来说包含以下几个运行时数据区:

其中的橙色区域是各个线程私有的,即每个线程都会有自己的一份,而绿色区域是各个线程共享的。

2.java对象的创建

类加载检查

当JVM扫描到new关键字时,首先会去检查这个指令的参数是否能够在常量池中定位到一个类的符号引用,并且检查这个类的符号引用代表的类是否已被加载、解析和初始化过。如果没有,就必须先执行相应的类加载过程。

内存分配

当类加载检查通过后,JVM需要为新生对象分配内存,即是把一块确定大小的内存从java堆中划分出来。常用的划分方法有两种:指针碰撞(要求堆内存绝对规整)、空闲列表(堆内存并不规整)。

内存初始化

JVM需要将分配到的内存空间都初始化为零值(不包括对象头),这就保证了对象的实例字段在java代码中可以不赋初始值就直接使用,也就是说程序能够访问到这些字段的数据类型所对应的零值。

对象初始化

执行方法,将对象按照程序员的意愿进行初始化。

3.对象的访问定位

对象创建好了,我们还希望能够快速的访问到这些对象,这就需要JVM栈上的reference(引用)数据来找到堆中的具体对象,而目前使用最多的访问方式有“句柄方式”和“直接指针”两种。

使用句柄方式访问的话,就需要在堆中划分一部分内存来作为句柄池,reference变量中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。

使用直接指针访问的话,reference变量中存储的直接就是对象地址,但是需要考虑如何放置类型数据的相关信息。

4.内存溢出异常

JVM运行时数据区除了PC寄存器之外,其他的内存区域都有可能发生内存溢出的异常情况。PC寄存器是唯一一个在JVM规范中没有规定任何OutOfMemoryError(OOM)情况的区域。

堆溢出

java中的堆用于存储对象实例,如果不断地创建对象,并且保证GC Roots到对象之间有可达路径以避免GC的回收处理,那么在对象的数量达到最大堆的容量限制后就会发生堆溢出的异常情况。

栈溢出(包括JVM栈和本地方法栈)

1.如果线程请求的栈深度大于JVM所允许的最大深度,将抛出StackOverflowError异常;

2.如果JVM在扩展栈时无法申请到足够的内存空间,将抛出OutOfMemoryError异常。

此外,还有方法区溢出、常量池溢出、本机内存溢出等等。

以上是Java内存管理和内存溢出异常的详解的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn