JVM学习(1)-虚拟机内存区域划分以及内存溢出

Java虚拟机的内存区域划分 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分成很多个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。Java虚拟机规范中把Java虚拟机所管理的内存划分为以下几个区域。   一、程序计数器(Program Counter Register)   程序计数器是一块较小的内存空间,它的作用是当前所执行的字节码的行号指示器。它是线程私有的,即各个线程都有独立的程序计数器。   如果线程正在 执行一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在 立即下载

点击查看更多JVM总结

Java虚拟机在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途以及创建和销毁的时间,有些区域会随着虚拟机进程的启动而存在,有的区域会依赖线程的创建和结束而建立和销毁。理解Java虚拟机内存区域的划分,会对对象的分配、内存的分配、堆栈溢出异常有进一步的了解。

【知识脑图】:http://naotu.baidu.com/file/0d12d244f1312a22495aa43e23844ead?token=3dbbf34935d1a82d
在这里插入图片描述

一、运行时数据区内存划分

1.1、图示

虚拟机的运行时数据主要可以划分为如下几个主要的内存区域,绿色部分为线程共享区域,白色部分为线程私有区域,其他部分会继续在下文继续解读。
在这里插入图片描述

1.2、线程私有的内存区域

线程私有的内存区域指的是每当一个线程创建时会开辟一块相应的内存空间,每个线程的私有空间数据不会共享。

  • 1、程序计数器
    程序计数器是一块很小的内存空间,它可以被看做是当前线程所执行的字节码行号指示器,线程需要执行的跳转、循环、中断等操作都需要依赖程序计数器去实现

  • 2、虚拟机栈
    虚拟机栈是线程私有的,与线程的生命周期相同(同生共死)。每个线程中的方法被创建时就会创建一个栈帧,用以存储局部变量表,方法出口信息,操作数栈等数据,每一个方法被调用直至执行完的过程都对应着一个栈帧的入栈和出栈的过程。
    开发者常说的“引用存储在栈中、实例存储在堆中“,其中的栈指的就是虚拟机栈中的局部变量表部分,而堆指的是Java堆。

  • 3、本地方法栈
    本地方法栈和虚拟机栈发挥的作用十分相似,不同的地方在于本地方法栈在线程调用本地方法时才会使用到。

1.3、线程共享的内存区域

线程共享的内存区域指的是方法区和Java堆区,这两个区域中的数据可以被不同的线程所访问到

  • 1、Java堆
    Java堆即平常说的堆区,它是虚拟机所管理的内存中最大的一块区域,Java堆区存在的唯一目的就是存放对象的实例,几乎所有的对象实例已经数组都会在堆上分配。
    由于Java堆是垃圾回收的主要区域,所以又被成为GC堆;由于现在的垃圾收集器都使用了分代回收算法,所以堆内存还能细分为新生代和老年代。(再细分可以分为Eden空间、Survivor空间等)。

  • 2、方法区
    方法区和Java堆一样是被所有线程所共享的区域,它用于存储虚拟机加载的类信息、常量和静态变量等信息;方法区有时又被称为永生代,因为这个区域不会频繁地发生垃圾回收。
    运行时常量池是方法区的一部分。Class文件中出了含有类的版本、字段和方法外,还有常量池,它用于存放编译器生成的各种字面量和符号引用,这部分内容会在类加载后进入运行时常量池中存放。

1.4、直接内存

在Java虚拟机中没有定义一块内存区域,它被称为直接内存,不属于虚拟机运行时数据区。在JDK1.4中新加入的NIO类引入了一种基于通道的I/O方式,它可以使用Native方法去直接调用直接内存,避免了在Java堆和Native堆之间频繁的复制数据,提高了运行效率。

二、各内存区域的溢出异常

由于各内存区域都存在内存的进出,故会存在内存的溢出异常,当然,程序计数器除外,因为它所占用的内存空间十分地小,并且不存在内存的出入,所以在Java虚拟机中没有对这块区域定义任何的内存异常。

2.0、虚拟机启动参数

Java虚拟机有许多启动参数可供我们配置,例如Java堆内存大小,虚拟机栈内存大小等,可以通过java -X命令查看:

arong@arong-ubuntu:~$ java -X
    -Xmixed           混合模式执行 (默认)
    -Xint             仅解释模式执行
    -Xbootclasspath:<用 : 分隔的目录和 zip/jar 文件>
                      设置搜索路径以引导类和资源
    -Xbootclasspath/a:<用 : 分隔的目录和 zip/jar 文件>
                      附加在引导类路径末尾
    -Xbootclasspath/p:<用 : 分隔的目录和 zip/jar 文件>
                      置于引导类路径之前
    -Xdiag            显示附加诊断消息
    -Xnoclassgc       禁用类垃圾收集
    -Xincgc           启用增量垃圾收集
    -Xloggc:<file>    将 GC 状态记录在文件中 (带时间戳)
    -Xbatch           禁用后台编译
    -Xms<size>        设置初始 Java 堆大小
    -Xmx<size>        设置最大 Java 堆大小
    -Xss<size>        设置 Java 线程堆栈大小
    -Xprof            输出 cpu 配置文件数据
    -Xfuture          启用最严格的检查, 预期将来的默认值
    -Xrs              减少 Java/VM 对操作系统信号的使用 (请参阅文档)
    -Xcheck:jni       对 JNI 函数执行其他检查
    -Xshare:off       不尝试使用共享类数据
    -Xshare:auto      在可能的情况下使用共享类数据 (默认)
    -Xshare:on        要求使用共享类数据, 否则将失败。
    -XshowSettings    显示所有设置并继续
    -XshowSettings:all
                      显示所有设置并继续
    -XshowSettings:vm 显示所有与 vm 相关的设置并继续
    -XshowSettings:properties
                      显示所有属性设置并继续
    -XshowSettings:locale
                      显示所有与区域设置相关的设置并继续

-X 选项是非标准选项, 如有更改, 恕不另行通知。
2.1、虚拟机栈溢出

虚拟机栈中被规定了两种异常:StackOverflowError以及OutOfMemoryError。

  • StackOverflowError

当线程请求的栈深度大于虚拟机所允许的深度时,无法将栈帧入栈,这时将抛出StackoverflowError异常,即当一个线程反复地调用方法时(每创建和结束一个方法对应着栈帧入栈和出栈的过程)可能会抛出这个异常,这在递归调用时会出现:

public class VMStackError {
    int stackLength = 1;

    public static void main(String[] args) {
        VMStackError vmStackError = new VMStackError();
        vmStackError.stackLeak();
    }

    public void stackLeak() {
        System.out.println(stackLength);
        //栈帧数量
        stackLength++;
        //递归调用
        stackLeak();
    }
}

运行main方法后抛出StackOverflowError异常,可以看到默认的配置下,当一个线程占用的虚拟机栈栈深度是10000左右,当达到这个限制时就会无法入栈。
在这里插入图片描述
现在使用虚拟机启动参数-Xss228k指定虚拟机栈内存为228k,运行main方法,发现只能存在1500左右个栈帧,说明启动参数生效了。

在这里插入图片描述

  • OutOfMemoryError
    这个异常发生在虚拟机在扩展栈时无法申请到足够的内存空间,也就是启动的线程过多,无法为每个线程都申请到一个虚拟机栈。
2.2、方法区和运行时常量池溢出

由于运行时常量池属于方法区的一部分,所以可以将两者放在一起测试。我们可以使用参数-XX:MaxPermSize来限制方法区的大小从而现在运行时常量池的大小,为了占用运行时常量池的内存,我们可以使用String.intern()方法,为没有在运行时常量池值的对象添加进去。

public class MethodAreaLeak {
    private static int i = 0;
    //-XX:MaxPermSize128k
    //-XX:PermSize128k
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        while (true) {
            list.add(String.valueOf(i).intern());
        }
    }
}

在这里插入图片描述

2.3、Java堆溢出

Java堆存放着绝大部分的对象实例,我们可以通过-Xms和-Xmx参数去控制Java堆内存的初始化大小和最大值

public class JavaHeap {
    //-Xms1024k
    //-Xmx1024k
    public static void main(String[] args) {
        ArrayList<Object> list = new ArrayList<>();
        while (true) {
            list.add(new JavaHeap());
        }
    }
}

运行main方法,出现Java堆内存溢出
在这里插入图片描述

深入解析Buck开关电源中的死区时间设计及其对系统性能的影响 本文深入解析了Buck开关电源中死区时间的设计原理及其对系统性能的关键影响。死区时间通过防止上下管同时导通来避免穿通电流,确保系统安全。文章详细探讨了其工作机制、设置时的效率与安全权衡,以及不当设置对效率、稳定性和EMI的连锁反应,并提供了基于实测的调试方法与实战案例。 阅读详情

相关推荐

【实战】ESP32 + LN298N 实现电动推杆的闭环位置伺服控制

本文详细介绍了如何使用ESP32微控制器和LN298N电机驱动模块,为普通电动推杆增加编码器反馈,实现精准的闭环位置伺服控制。文章从硬件选型与接线讲起,深入解析了编码器四倍频计数原理与位置换算,并重点阐述了PID控制算法的核心思想、代码实现及参数整定方法,旨在帮助读者从零构建一个反应迅速、定位精准的智能执行器系统。

weixin_29195615的博客 320

深入理解java虚拟机——堆区,学习java内存分布这一篇就够了

在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务实际上便等同于把一块确定大小的内存块从Java堆中划分出来。 假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump The Pointer) 但如果Java堆中的内存并不是规整的,已被使用的内存和空闲的内

gaohaicheng123的博客 3574

SPARTAN6 + Verilog - FPGA step by step 从0开始学习(1)

SPARTAN6 + Verilog - FPGA step by step 从0开始学习(1)Step 1 软件安装Step 2 硬件获取Step 3 开始从头到脚建一个工程Step 3.1 新建一个工程 从0开始学习FPGA,最好的办法就是先建一个最简单的模块,并且跑起来,然后再慢慢展开。下面这个例子是要按照一定的周期点亮核心板上的一个led。 Step 1 软件安装 这个从0开始学习是用的xilinx的SPARTAN6。SPARTAN6集成开发环境用ISE,不能用Vivado,各自对应的版本不同。安装

xfacexx点点记录 5517

JVM内存区域划分

JVM运行时,将内存空间划分为堆、方法区、程序计数器、虚拟机栈和本地方法栈5个区域来管理。

tianyuxu的博客 599

用大白话讲解Carplay(原创)

用大白话讲解Carplay: Carplay是美国苹果公司开发的一套服务,用户通过这套服务可以将iPhone与车载系统连接,然后在车载大屏上操作使用iPhone手机。个人理解,Carplay不能叫车载系统,不是操作系统,只能算一种服务。让你在车上的大屏上使用iPhone,这样用起来更方便,不需要在手机小屏幕上操作。基于这一点,有些人也说Carplay就是个投屏的功能,将手机屏幕投屏到了车机大屏上。可以简单这么理解,但是并不只是投屏这么简单,如果只是投屏的话,车子只是起到了一个显示器的功能,其实不止,手机和

cici2013的专栏 2万+

YOLOv8改进---BiFPN特征融合

yolov8结合BiFPN进行改进

qq_41920323的博客 4524

JVM实战1-JVM虚拟机内存区域划分

JVM内存区域划分

bangqin's blog 434

ROS从入门到精通0-4:VSCode 搭建 ROS 工程环境

为了提高开发效率,可以先安装集成开发工具和使用方便的工具,本教程用VSCode搭建ROS工程环境

FRIGIDWINTER的博客 1万+

JVM五:内存分区之线程共享区—堆

Java 虚拟机规范》中对堆的描述为:所有对象实例以及数组都应当在运行时分配在堆上。《Java 虚拟机规范》规定:堆可以处于物理上不连续的内存空间中,但在逻辑上它应该是被视为连续的。其大小是可以调节的。所有的线程共享 Java 堆内存,也可以在内划分线程私有的缓冲区(Thread Local Allocaltion Buffer,TLAB)方法结束后、堆中的对象不会马上被清理,仅在垃圾回收时才会被清理。堆是垃圾回收的重点区域。

白云苍狗 941

Python 爬虫实战:亚马逊商品评论 + 评分抓取(情感分析数据预处理)

在电子商务领域,用户评论是了解产品口碑和市场反馈的重要渠道。亚马逊作为全球领先的电商平台,拥有海量的商品评论数据。本文将详细介绍如何使用 Python 编写爬虫程序,从亚马逊网站抓取商品评论和评分数据,并进行情感分析的数据预处理。

yansideyucsdn的博客 770

R语言caret拟合模型:train函数构建xgBoost Dart模型、模型调优、自定义设置trainControl函数和tuneLength参数

R语言caret拟合模型:train函数构建xgBoost Dart模型、模型调优、自定义设置trainControl函数和tuneLength参数

statistics+insight+vista+power 530

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

背景   JVM是Java开发的必备技能,JVM相当于Java的操作系统。   JVM(java virtual machine)即Java虚拟机,是运行java class文件的程序。   Java代码经过Java编译器编译,会编译成class文件, 是一种与平台无关的代码格式。   class文件按照JVM规范,包括java代码运行所需要的【元数据】和【代码】等内容。   JVM加载...

qq_24047659的博客 626

2024全国村级行政边界数据

五级行政区划:村边界数据产品涵盖五级行政区划:(一级行政区)省级行政区共31个其中:(台湾、香港、澳门除外);(二级行政区)地级行政区共334个其中:7个地区、3个盟、30个自治州、294个地级市;(三级行政区)县级行政区共2851个其中:1355个县、117个自治县、49个旗、3个自治旗、363个县级市、962个市辖区、1个林区、1个特区;(四级行政区)乡级行政区共40497个其中:11626个乡、1034个民族乡、20117个镇、7566个街道、151个苏木、1个民族苏木、2个县辖区公所;

J_Giser的博客 3236

深入理解Java虚拟机-Java内存区域与内存溢出异常

Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来。 文章目录概述运行时数据区域程序计数器(线程私有)Java虚拟机栈(线程私有)局部变量表操作数栈动态链接方法返回地址小结本地方法栈(线程私有)Java堆(全局共享)方法区(全局共享)运行时常量池直接内存HotSpot虚拟机对象探秘对象的创建1.判断对象对应的类是否加载、链接、初始化2.为对...

ThinkWon的博客 2万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

JVM 深入笔记(1)内存区域是如何划分的?

JVM 深入笔记(1)内存区域是如何划分的?作者:柳大 · Poechant电邮:zhongchao.ustc#gmail.com (#->@)博客:blog.youkuaiyun.com/poechant日期:Feb. 21st 2012一个超短的前言JVM 是一个从事 Java 开发的软件工程师的修炼之路上必然要翻阅的一座山。当你了解了 Java 的基本语言特性,当你熟悉了 Java SDK 中的常用 A

麦克船长的技术笔记 2万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

JDK1.8 JVM内存划分

首先先来看看1.7和1.8的时候JVM的划分是什么样的: (原图地址:https://www.processon.com/view/link/5b61ea2ae4b0555b39cfa842) 从这张图可以看到JDK1.8和JDK1.7相比最大的区别是:元空间区取代了永久代,永久代原本主要存放Class和Meta的信息。而元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不...

吃四碗饭的嘤嘤怪的博客 1万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【量产】JVM内存区域划分

本次仅讨论JVM内存的自动分配里的部分知识:JVM内存区域的划分

liangcheng0523的博客 1万+

JVM内存区域划分(堆、栈、方法区等)‌

通过合理配置JVM参数(如堆大小、栈大小、元空间限制)和代码优化(如避免内存泄漏),可有效避免内存溢出问题。‌:Java 8前为永久代(方法区实现),Java 8+为元空间(本地内存)。‌:记录当前线程执行到的字节码指令地址(分支、循环、异常处理等依赖它)。‌:为JVM调用Native方法(如C/C++库)提供栈空间。(Java 7及之前):如动态生成大量类(反射、CGLib)。‌:方法执行时的临时数据存储区(如算术运算的中间结果)。

大牛 1071

《深入理解Java虚拟机》Java虚拟机内存区域与内存溢出异常

在学习Java的过程中,了解Java虚拟机(JVM)的内存管理机制是至关重要的。特别是在处理大型项目或复杂应用时,对JVM内存区域的深入理解能够帮助我们更好地优化代码,避免内存泄漏和内存溢出等问题。

2401_86224057的博客 1786

JVM之Java内存区域与内存溢出异常

例如,在JDK 6或更早版本中,String.intern() 方法会将其内容复制到永久代的字符串常量池中,如果调用 intern() 的字符串过多,也会导致永久代溢出。检查应用是否使用了动态生成类的技术,或者是否存在类加载器泄漏(例如,在Web容器中重复部署应用时,旧的类加载器及其加载的类没有被卸载)。,是指程序在申请内存时,没有足够的内存空间供其使用。如果是内存溢出,检查业务逻辑是否合理,或者考虑增加堆内存大小(-Xmx),优化数据结构(如使用更节省内存的结构),或者分批处理大数据。

2301_77037373的博客 830

JVM内存区域划分与OutOfMemoryError详解

的区域,以及采取相应的解决和预防策略,开发者可以大大提高Java应用程序的稳定性和性能。随着Java技术的不断发展和演进,未来可能会有更多先进的内存管理技术和工具出现,以帮助我们更好地解决内存相关的问题。因此,作为Java开发者,我们需要保持持续的学习和探索精神,以应对不断变化的技术挑战。Java虚拟机(JVM)在执行Java程序时,会将其内存划分为几个不同的区域。这些区域有各自的用途和生命周期,了解它们的特性和可能遇到的问题,对于优化Java程序性能、排查内存泄漏等问题至关重要。一、JVM内存区域划分。

让每一行代码都有改变世界的力量 995

JVM内存区域划分精讲 上

大家好,我们又见面了。有小伙伴说 JVM 内存区域在学习与面试的时候常常理不清,为了解决这位小伙伴的困扰,我将通过两篇文章为大家理清 JVM 内存区域划分,这篇是第一篇将为大家介绍 JVM 内存区域的逻辑概念,下一篇将和大家唠一唠 HotSpot 虚拟机实现的一些小细节。安全带系好,发车咯!首先我们来明确一下运行时数据区的概念,Java 虚拟机在执行 Java 程序的过程中会将它所管理的内存划分为若干不同的数据区,这些数据区就是运行时数据区,这些区域有各自的用途和生命周期。根据《Java 虚拟机规范》的规定

weixin_44584422的博客 1024

JVM内存区域与内存溢出异常

对于Java程序员来说,Java虚拟机是再熟悉不过了,尤其是对Hotspot VM最熟悉了,因为它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广泛的Java虚拟机。相比C、C++开发人员来说,有了JVM,Java程序员不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄漏和内存溢出的问题。但也正因为内存控制完全交由JVM,一旦出现内存泄漏和溢出的问...

Helon的博客 1182

谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?(jvm)

JVM 内存区域的划分有助于管理不同类型的数据和信息,并优化垃圾回收和内存分配。以下是各区域可能发生的堆(Heap)方法区(Method Area)虚拟机栈(JVM Stack)本地方法栈(Native Method Stack)需要注意的是,程序计数器是不会发生内存溢出的。理解 JVM 内存区域的划分及其可能发生的错误,有助于开发人员更好地调优应用程序,避免和处理内存相关的问题。

喜欢猪猪 1477

JVM内存区域划分&垃圾回收

学习笔记之JVM 一、JVM基础知识 二、JVM的内存区域划分 2.1 程序计数器 2.2 Java虚拟机栈 2.3 本地方法栈 2.4 Java堆(Heap) 2.5 方法区 三、GC 3.1 基础术语 3.2 常见的垃圾收集算法 3.3 GC垃圾回收器

LX2016341134的博客 1872

【JVM】谈谈JVM内存区域的划分

对 Java 程序员来说我们不用自己手动管理对象内存的申请与释放,全部交由 Java 虚拟机(JVM)来管理内存的分配与回收。 因此,日常开发中我们不用关心内存分配与回收,减少了很多繁琐的工作,大大提高了开发效率。 也正是因为如此,一旦出内存泄漏和溢出方面的问题,如果不了解 JVM 内部的内存结构、工作机制,那么排查问题将变得异常艰难。 接下来,我们一起学习 JVM 内存区域的划分、作用以及可能产生的问题。 根据 Java 虚拟机规范,Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为几

Geek_ymv的专栏 734
上一篇: 计算机组成原理-原码、反码、补码和基本类型长度的计算
下一篇: 算法学习笔记(8)-归并排序
BoringRong
BoringRong 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 2万+粉丝 386原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoringRong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值