Java的内存区域与内存溢出异常你了解吗

  • 更新时间:2022-10-09 08:51:07
  • 编辑:蒯康裕

1. 运行时数据区域

在这里插入图片描述

1. 程序计数器(线程私有)

当前线程所执行的字节码的行号指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都要考程序计数器。(记住程序当前走到的位置,下次还回来)。线程私有。

2. Java虚拟机栈(线程私有)

和方法相关联,每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程

线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常(常见的递归层数过多导致”爆栈“)

3. 本地方法栈(线程私有)

类似于Java虚拟机栈。区别在于:

虚拟机栈为虚拟机执行Java方法本地方法栈则为虚拟机使用到的Native方法服务

Java开头通过Java Native Interface来调用本地方法(一般用C语言编写)

4. Java堆(线程共享)

Java虚拟机所管理的内存中最大的一块new出来的对象就存在于堆上垃圾收集器管理的主要区域

5. 方法区(线程共享)

存储已被虚拟机加载的类信息、常量、静态变量

6. 运行时常量池

方法区的一部分用于存放编译期生成的各种字面量和符号引用

2. 对象是如何创建的?

Object obj=new Object(): 分析这行代码的执行过程

使用了new关键字,检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。没有的话先加载类类加载检查通过后,虚拟机将为新生对象分配内存内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值虚拟机要对对象进行必要的设置,例如将对象的哈希码、元数据、GC分代年龄、是否使用偏向锁等数据存放在对象头中执行init方法,把对象按照程序员的意愿进行初始化(给成员变量赋的值)

3. 对象的内存布局

在这里插入图片描述

在这里插入图片描述

4. 对象的访问定位

1. 句柄访问

Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息

在这里插入图片描述

2. 直接指针访问

Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址

在这里插入图片描述

二者比较:

使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,即使对象被移动(GC过程),只需要改变句柄中的示例指针,无需变动refrence直接指针访问方式的最大好处就是速度更快, refrence直接指向实例数据,减少了一次指针访问

HotSpot虚拟机使用直接指针方式进行对象访问的

5. OutOfMemoryError异常代码演示

1. Java堆溢出

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

在这里插入图片描述

在这里插入图片描述

限制Java堆的大小为20MB,不可扩展(将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展),通过参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析

2. 虚拟机栈溢出

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

package jvm;
import java.util.ArrayList;
import java.util.List;
public class OutOfMemoryErrorDemo {
	static int i=0;
	public static void main(String[] args) {
		f();
	}
	public static void f() {
		System.out.println(i++);
		f();
	}
}

在这里插入图片描述

在这里插入图片描述

相同的Xss(线程的堆栈大小)下,如果栈中的本地数据较多,那么相应的可以递归的次数就越少

还有1种栈溢出会报OutOfMemoryError异常,如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常,比如将上面的递归改成多线程版就会出现这种问题

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注码农之家的更多内容!  

相关教程

  • Java8简单了解Lambda表达式与函数式接口

    为网友们分享了关于Java8的教程,这篇文章主要介绍了Java8简单了解Lambda表达式与函数式接口,具有一定参考价值,需要的朋友可以了解下。

    发布时间:2022-07-11

  • 解决java向mysql插入数据乱码的方法

    这篇文章主要为大家详细介绍了java向mysql插入数据乱码问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    发布时间:2021-06-02

  • 实例详解hadoop中实现java网络爬虫

    下面小编就为大家带来一篇hadoop中实现java网络爬虫(示例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    发布时间:2020-03-22

  • Java设计中Builder模式实例详解

    这篇文章主要介绍了从一个Person例子进行分析重叠构造器模式、Builder模式的使用场景以及运用JavaBeans模式弥补重叠构造器模式的不足

    发布时间:2019-11-22

  • 详解java基本数据类型传递与引用传递区别

    这篇文章主要介绍了java基本数据类型传递与引用传递区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    发布时间:2020-02-05

  • Java StringBuffer类与StringBuilder类的实例用法

    这篇文章主要介绍了Java StringBuffer类与StringBuilder类用法,结合实例形式总结分析了Java StringBuffer类与StringBuilder类的功能、原理及添加、删除、替换、截取等操作实现技巧,需要的朋友可以参考下

    发布时间:2019-07-03

  • java生成将图片存入数据库的sql语句方法实例

    这篇文章主要介绍了详解JAVA生成将图片存入数据库的sql语句实现方法的相关资料,这里就是实现java生成图片并存入数据库的实例,需要的朋友可以参考下

    发布时间:2020-06-11

  • Java实现顺序表的增删查改功能

    Java实现顺序表的增删查改功能

    给网友们整理关于Java的教程,这篇文章主要介绍了Java实现顺序表的增删查改功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

    发布时间:2022-09-12

用户留言