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

 更新时间:2022年03月15日 14:44:20   作者:CodePanda@GPF  
这篇文章主要为大家详细介绍了Java的内存区域与内存溢出异常,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

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异常,比如将上面的递归改成多线程版就会出现这种问题

总结

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

相关文章

  • Java Stream 流中 Collectors.toMap 的用法详解

    Java Stream 流中 Collectors.toMap 的用法详解

    这篇文章主要介绍了Stream 流中 Collectors.toMap 的用法,Collectors.toMap()方法是把List转Map的操作,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-01-01
  • Java防止短信盗刷和轰炸的解决方案

    Java防止短信盗刷和轰炸的解决方案

    短信盗刷和短信轰炸是项目开发中必须要解决的问题之一,它的优先级不亚于 SQL 注入的问题,今天我们就来看下,如何防止这个问题,需要的朋友可以参考下
    2024-02-02
  • 在springboot项目中同时接收文件和多个参数的方法总结

    在springboot项目中同时接收文件和多个参数的方法总结

    在开发接口中,遇到了需要同时接收文件和多个参数的情况,可以有多种方式实现文件和参数的同时接收,文中给大家介绍了两种实现方法,感兴趣的同学跟着小编一起来看看吧
    2023-08-08
  • Java几个实例带你进阶升华下篇

    Java几个实例带你进阶升华下篇

    与其明天开始,不如现在行动,本文为你带来几个Java书写的实际案例,对巩固编程的基础能力很有帮助,快来一起往下看看吧
    2022-03-03
  • MyBatis-Plus自定义SQL的详细过程记录

    MyBatis-Plus自定义SQL的详细过程记录

    Java开发使用mybatis-plus来执行sql操作,往往比mybatis能够省时省力,下面这篇文章主要给大家介绍了关于MyBatis-Plus自定义SQL的相关资料,需要的朋友可以参考下
    2022-02-02
  • Springboot中的自定义拦截器及原理详解

    Springboot中的自定义拦截器及原理详解

    这篇文章主要介绍了Springboot中的自定义拦截器及原理详解,拦截器主要是用于在用户请求控制中,对于请求识别,鉴权,以及区分资源是否可以被目标方法调用的安全机制,需要的朋友可以参考下
    2023-12-12
  • 深入浅析TomCat Session管理分析

    深入浅析TomCat Session管理分析

    这篇文章主要介绍了深入浅析TomCat Session管理分析,需要的朋友可以参考下
    2015-11-11
  • 新手初学Java集合框架

    新手初学Java集合框架

    这篇文章主要介绍了JAVA集合框架的相关知识,文中讲解非常细致,帮助大家更好的理解学习JAVA框架,感兴趣的朋友快来了解下,希望能给你带来帮助
    2021-07-07
  • java如何用反射将一个对象复制给另一个对象

    java如何用反射将一个对象复制给另一个对象

    这篇文章主要介绍了java如何用反射将一个对象复制给另一个对象问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • Java容器类的深入理解

    Java容器类的深入理解

    本篇文章是对Java容器类进行了详细的分析介绍,需要的朋友参考下
    2013-06-06

最新评论