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

目录
  • 1.运行时数据区域
    • 1.程序计数器(线程私有)
    • 2.Java虚拟机栈(线程私有)
    • 3.本地方法栈(线程私有)
    • 4.Java堆(线程共享)
    • 5.方法区(线程共享)
    • 6.运行时常量池
  • 2.对象是如何创建的?
  • 3.对象的内存布局
  • 4.对象的访问定位
    • 1.句柄访问
    • 2.直接指针访问
  • 5.OutOfMemoryError异常代码演示
    • 1.Java堆溢出
    • 2.虚拟机栈溢出
  • 总结

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

总结

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

(0)

相关推荐

  • Java内存区域和内存模型讲解

    一.Java内存区域 方法区(公有):用户存储已被虚拟机加载的类信息,常量,静态常量,即时编译器编译后的代码等数据.异常状态 OutOfMemoryError. 堆(公有):是JVM所管理的内存中最大的一块.唯一目的就是存放实例对象,几乎所有的对象实例都在这里分配.Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为"GC堆".异常状态 OutOfMemoryError. 虚拟机栈(线程私有): 描述的是java方法执行的内存模型:每个方法在执行时都会创建一个栈帧,用户存储局部变

  • Java内存区域与内存溢出异常详解

    Java内存区域与内存溢出异常 概述 对于 C 和 C++程序开发的开发人员来说,在内存管理领域,程序员对内存拥有绝对的使用权,但是也要主要到正确的使用和清理内存,这就要求程序员有较高的水平. 而对于 Java 程序员来说,在虚拟机的自动内存管理机制的帮助下,不再需要为每一个 new 操作去写配对的 delete/free 代码,而且不容易出现内存泄漏和内存溢出问题,看起来由虚拟机管理内存一切都很美好.不过,也正是因为 Java 程序员把内存控制的权力交给了 Java 虚拟机,一旦出现内存泄漏和

  • Java常见内存溢出异常分析与解决

    Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等,而Hotspot jvm的实现中,将堆内存分为了三部分,新生代,老年代,持久带,其中持久带实现了规范中规定的方法区,而内存模型中不同的部分都会出现相应的OutOfMemoryError错误,接下来我们就分开来讨论一下.java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都出于以下原因: JVM内存过小.程序不严密,产生了过多的垃圾. 导致OutOfMemor

  • 简单了解JAVA内存区域效果知识

    这篇文章主要介绍了简单了解JAVA内存区域效果知识,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JAVA内存区域介绍 程序计数器: 线程私有,很小的内存空间,可以看做是当前线程所执行的字节码的行号指示器: 每个线程都有一个独立的程序计数器,各个线程之间的计数器相互不影响,独立存储: 如果线程执行的是Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果是一个Native方法,那么这个计数器的值则为undefined: 该内存

  • Java中内存区域的划分与异常详解

    前言 JAVA内存区域主要由程序计数器.java 虚拟机栈.本地方法栈.Java堆.方法区以及运行时常量池组成.本文将给大家详细介绍关于Java内存区域的划分与异常的相关内容,下面话不多说了,来一起看看详细的介绍吧. 运行时数据区域 JVM在运行Java程序时候会将内存划分为若干个不同的数据区域. 程序计数器 线程私有.可看作是 当前线程所执行的字节码的行号指示器 ,字节码解释器的工作是通过改变这个计数值来读取下一条要执行的字节码指令. 多线程是通过线程轮流切换并分配处理器执行时间来实现的,任何

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

    目录 1.运行时数据区域 1.程序计数器(线程私有) 2.Java虚拟机栈(线程私有) 3.本地方法栈(线程私有) 4.Java堆(线程共享) 5.方法区(线程共享) 6.运行时常量池 2.对象是如何创建的? 3.对象的内存布局 4.对象的访问定位 1.句柄访问 2.直接指针访问 5.OutOfMemoryError异常代码演示 1.Java堆溢出 2.虚拟机栈溢出 总结 1. 运行时数据区域 1. 程序计数器(线程私有) 当前线程所执行的字节码的行号指示器,分支.循环.跳转.异常处理.线程恢复

  • 学习JVM之java内存区域与异常

    一.前言 java是一门跨硬件平台的面向对象高级编程语言,java程序运行在java虚拟机上(JVM),由JVM管理内存,这点是和C++最大区别:虽然内存有JVM管理,但是我们也必须要理解JVM是如何管理内存的:JVM不是只有一种,当前存在的虚拟机可能达几十款,但是一个符合规范的虚拟机设计是必须遵循<java 虚拟机规范>的,本文是基于HotSpot虚拟机描述,对于和其它虚拟机有区别会提到:本文主要描述JVM中内存是如何分布.java程序的对象是如何存储访问.各个内存区域可能出现的异常. 二.

  • 浅谈java内存管理与内存溢出异常

    说到内存管理,笔者这里想先比较一下java与C.C++之间的区别: 在C.C++中,内存管理是由程序员负责的,也就是说程序员既要完成繁重的代码编写工作又要时常考虑到系统内存的维护 在java中,程序员无需考虑内存的控制和维护,而是交由JVM自动管理,这样就不容易出现内存泄漏和溢出的问题.然而,一旦出现内存泄漏和溢出方面的问题,如果不了解JVM的内存管理机制就很难找到错误所在. 1.JVM运行时数据区 JVM在运行java程序的时候会将它所管理的内存划分为若干个不同的区域,这些区域不仅有自己的用途

  • Java编程常见内存溢出异常与代码示例

    Java 堆是用来存储对象实例的, 因此如果我们不断地创建对象, 并且保证 GC Root 和创建的对象之间有可达路径以免对象被垃圾回收, 那么当创建的对象过多时, 会导致 heap 内存不足, 进而引发 OutOfMemoryError 异常. /** * @author xiongyongshun * VM Args: java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError */ public class OutOfMemoryErrorTe

  • Java 常见的几种内存溢出异常的原因及解决

    内存溢出的异常有很多,并且每种内存溢出都会有不同的异常信息和解决方式,下面会列出常见的几种内存溢出异常 堆内存溢出 java.lang.OutOfMemoryError: Java heap space 原因: 当堆内存不足,并且已经达到JVM设置的最大值,无法继续申请新的内存,存活的对象在堆内存中无法被回收,那么就会抛出该异常,表示堆内存溢出. 当一次从数据库查询大量数据,堆内存没有足够的内存可以存放大量的数据 大量的强引用对象在堆内存中存活,GC无法回收这些对象,新创建的对象在新生代无法进行

  • Java虚拟机内存区域划分详解

    在谈 JVM 内存区域划分之前,我们先来看一下 Java 程序的具体执行过程,我画了一幅图. Java 源代码文件经过编译器编译后生成字节码文件,然后交给 JVM 的类加载器,加载完毕后,交给执行引擎执行.在整个执行的过程中,JVM 会用一块空间来存储程序执行期间需要用到的数据,这块空间一般被称为运行时数据区,也就是常说的 JVM 内存. 所以,当我们在谈 JVM 内存区域划分的时候,其实谈的就是这块空间--运行时数据区. 大家应该对官方出品的<Java 虚拟机规范>有所了解吧?了解这个规范可

随机推荐