JVM学习笔记2.0

从0开始学习JVM C语言申请内存:malloc freec/C++ 手动回收内存Java: new?忘记回收多次回收没有任何引用指向的一个对象或者多个对象(循环引用)根据需求进行JVM规划和预调优优化运行JVM运行环境(慢,卡顿)解决JVM运行过程中出现的各种问题(OOM) 阅读详情

1.运行时数据区域

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。

  • 程序计数器

        程序计数器(Program Counter Register)是一块较小的内存空向,它可以看作是当前线程所执行的字节码的行号指示器。在虚似机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作肘就是通过改变这个计数器的値来选取下一条需要抉行的字节码指令分支、循环、跳装、异常处理、线程恢夏等基础功能都需要依赖这个计数器来完成。
        如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。 此内存区域是唯- 一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

  • Java虚拟机栈

        Java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中人栈到出栈的过程。
        在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

  • 本地方法栈

        本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,它们之间的区别是虚拟机栈为虚拟机执行Java方法( 也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。
        本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

  • Java堆

        Java堆是垃圾收集器管理的主要区域。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。如果在堆中没有完成实例分配,并且堆也再无法扩展时,将会抛出OutOfMemoryError异常。

  • 方法区

        与堆一样,也是各个线程共享的一块内存区域。特别地,在HotSpot虚拟机上,很多人称方法区为永久代。,当无法再申请到内存时,会抛出OutOfMemoryError异常。

  • 运行时常量池

        是方法区的一部分,同样受到方法区内存的限制,当无法再申请到内存时,会抛出OutOfMemoryError异常。

  • 直接内存

        直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。
        NIO可以直接分配堆外内存。

2.hotspot中对象的内存布局

Hotspot虚拟机中,对象在内存中的存储布局分为三部分:

    Header(对象头)
    
        自身运行时数据(32位~64位MarkWord):哈希值、GC分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳。
        类型指针
        
    InstanceData:数据实例,即对象的有效信息,相同宽度(如long和double)的字段被分配在一起,父类属性在子类属性之前。    

    Padding:占位符填充内存

3.对象的访问定位

  • 句柄访问

    最大好处是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改

  • 直接指针访问

    最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在Java中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。Hotspot使用直接指针访问。

4.内存溢出OutOfMemoryError

  • Java堆溢出

    Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。
    Java堆内存的0OM异常是实际应用中常见的内存溢出异常情况。当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进.步提示“Java heap space"。
    如果是内存泄露,可进一步通过查看泄露对象到GC Roots的引用链,就能找到泄露对象是通过怎样的路径与GCRoots相关联并导致垃圾收集器无法自动回收它们的。掌握了泄露对象的类型信息及GCRoots引用链的信息,就可以比较准确地定位出泄露代码的位置。
    如果是不存内存在泄露,应当检查虚拟机的堆参数(-Xmx 与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

  • 栈溢出

    hotspot虚拟机并不区分虚拟机栈和本地方法栈。如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMermoryEror异常。
    在单线程下,无论是由于栈帧太大还是虛拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。多线程情况下,为每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。

  • 常量区和方法区

    提示:java.lang.OutOfMemoryError:PermGen space

5.垃圾回收(GC)

  • 标记清除算法

    主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高:另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

  • 复制算法(多用于新生代)

    将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的900%(80%+10%),只有10%的内存会被“浪费”。如果另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代。
    复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。

  • 标记整理算法(多用于老年代)

根据老年代的特点,提出了另外一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向-端移动,然后直接清理掉端边界以外的内存。

  • 分代收集算法

    Java 虚拟机将堆分为新生代和老年代,并且对不同代采用不同的垃圾回收算法。其中,新生代分为 Eden 区和两个大小一致的 Survivor 区,并且其中一个 Survivor 区是空的。
    在只针对新生代的 Minor GC 中,Eden 区和非空 Survivor 区的存活对象会被复制到空的 Survivor 区中,当 Survivor 区中的存活对象复制次数超过一定数值时,它将被晋升至老年代。
    因为 Minor GC 只针对新生代进行垃圾回收,所以在枚举 GC Roots 的时候,它需要考虑从老年代到新生代的引用。为了避免扫描整个老年代,Java 虚拟机引入了名为卡表的技术,大致地标出可能存在老年代到新生代引用的内存区域。

6.对象分配

对象分配原则:   
1.对象优先在eden分配
2.大对象直接进入老年代
3.长期存活的对象将进入老年代
4.动态对象年龄判定

7.类加载

    1.七个阶段:
    加载,验证,准备,解析,初始化,使用,卸载。验证,准备,解析三个部分统称为连接。

    2.对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。

    3.类加载器类型

  • 启动类加载器(Bootstrap ClassLoader)
  • 扩展类加载器(Extension ClassLoader)
  • 应用程序类加载器(Application ClassLoader)

    4.双亲委派模型

    双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器丢完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到项层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
    使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。

    5.破坏双亲委派模型

    双亲委派很好地解决了各个类加载器的基础类的统一问题(越基础的类由越上层的加载器进行加载),基础类之所以称为“基础”,是因为它们总是作为被用户代码调用的API,但是如果基础类又要调用回用户的代码时,启动类加载器不“认识”这些代码,为了解决这个问题,Java设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLcader)。这个类加载器可以通过java.lang.Thread类的setContextClassLoaser()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。
    有了线程上下文类加载器,就可以使用这个线程上下文类加载器去加载所需要的SPI代码,也就是父类加载器请求子类加载器去完成类加载的动作,这种行为实际上就是打通了双亲委派模型的层次结构来逆向使用类加载器,实际上已经违背了双亲委派模型的-般性原则,但这也是无可奈何的事情。Java中所有涉及SPI的加载动作基本上都采用这种方式,例如JNDI、JDBC、 JCE、 JAXB和JBI等。

8.Java语法糖

  • 泛型擦除
  • 自动拆装箱
  • 遍历循环
  • 条件编译
UART中断接收的实战陷阱:HAL库常见误区与性能调优指南 本文深入解析STM32 HAL库UART中断接收机制,揭示常见实战陷阱如数据溢出、中断优先级配置不当等,并提供性能调优方案。重点介绍如何使用空闲中断处理不定长数据、DMA与中断混合模式优化,以及工业级错误恢复与流量控制策略,帮助开发者构建稳定可靠的串口通信系统。 阅读详情

相关推荐

Globus数据下载全攻略:从零配置到批量下载大文件(附常见问题解决)

本文详细介绍了Globus数据下载的全流程,从零配置到批量下载大文件的实用技巧,包括环境准备、高级传输策略、性能优化及常见问题解决方案。Globus作为科研数据的高效传输工具,通过并行流传输和自动校验技术,显著提升大规模数据传输的效率和可靠性。

u9v0w的博客 662

2.0JVM

jvm的简介,以及运行过程

weixin_46194000的博客 191

从仿真曲线到电路状态:用Cadence Virtuoso深度剖析CS放大器各个工作区(以电流源负载为例)

本文通过Cadence Virtuoso平台,深入剖析电流源负载CS放大器在不同工作区的表现,从仿真曲线解读电路状态。详细介绍了如何通过Vout-Vin直流扫描曲线判断MOS管工作区域(截止区、饱和区、线性区),并验证理论与仿真的一致性,提升模拟IC设计调试效率。

weixin_30940783的博客 442

重读 JVM

秋招开始了,前面由于做别的事耽误了半个月,以前学的东西不用就很容易忘记。所以,这次重新阅读《深入理解 JVM 虚拟机》时,想做一个记录。将碎片的知识整合,方便自己以后阅读,同时也和大家一起分享。内容中会添加我自己的理解,其中如果有错误,欢迎大家指正。 相关阅读:1. 重拾数据结构2. 重拾操作系统3. 重拾计算机网络(未完成))注意:以上内容会持续更新,欢迎大家关注 GitHub &&...

weixin_34009794的博客 5359

机器学习-02 模型的评估与选择

2.1 误差与过拟合 我们将学习器对样本的实际预测结果与样本的真实值之间的差异成为:误差(error)。定义: 在训练集上的误差称为训练误差(training error)或经验误差(empirical error)。 在测试集上的误差称为测试误差(test error)。 学习器在所有新样本上的误差称为泛化误差(generalization error)。 显然,我们希望得到的是在新样本上表现得很好的学习器,即泛化误差小的学习器。因此,我们应该让学习器尽可能地从训练集中学出普适性的“一般特征”,这

一个小白 1704

第1章:Zephyr 开发环境搭建与 Hello World

📝【摘要】本文是Zephyr RTOS开发入门指南的第一章,详细介绍了从环境搭建到首个应用运行的完整流程。主要内容包括:1️⃣ Zephyr项目结构解析与west工具链部署;2️⃣ 开发环境配置(Linux/WSL)及SDK安装;3️⃣ 两种实践路径——官方HelloWorld样例与自定义应用开发;4️⃣ 实际硬件部署方法(nRF/STM32)及常用west命令速查;5️⃣ 典型问题解决方案。通过qemu_x86模拟器演示了基础打印功能实现,为后续深度开发奠定基础。

hemoparrot的专栏 1361

JVM学习笔记(1)-JVM总体篇

目录 0 前言 1 Java体系描述 1.1 Java体系构成 1.2 Java平台描述 2 JVM体系描述 2.1 JVM基本概念 2.2 ​​​​​​​JVM运行原理 3 示例 参考 0 前言      最近买了周志明的《深入理解Java虚拟机 JVM高级特性与最佳实践 》,结合网上的相关文章资料,尝试做一套JVM学习笔记,也算整理和巩固。相关引用文章,已罗列在参考篇中,...

wingsing2010的专栏 4700

Blazor Session设置

微软官方封装了一些浏览器的操作,其中就有Session的操作的封装ProtectedSessionStorage 微软文档因为我们知道,依赖注入的生命周期是Singleton程序Scoped网页:刷新,url直接跳转都会重置。Transient路由C# Blazor 学习笔记(10):依赖注入但是没有一个和浏览器绑定的生命周期。即浏览器关闭才会退出。这个是后端无法获取的,因为后端根本不知道浏览器何时关闭。这个只能用浏览器自带的缓存。

qq_44695769的博客 1788

JVM 基础知识学习笔记

JVM 一个运行在计算机上的程序,它的职责是运行 Java 字节码文件。

Gjw_java的博客 1155

【UE5】UE5 Dedicated Server专用服务器与网络同步

这篇文章是个人在学习UE4的网络同步方面的内容的一些记录,因为UE5出来了,顺带也一起熟悉熟悉UE5,所以也就直接使用UE5来实践了。说句实在话,UE4网络同步这块确实挺难的,我自己在网上搜索的博客的内容要么停留在很浅层面只搭建一个ds服务器,要么就直接深入源码去剖析UE4的网络机制,处在中间层面的内容少之又少,不得不自己好一阵研究,强烈推荐这几位博主的博文,我在学习的过程中也从中受益匪浅。 Ken_An、风蚀之月、 刘东无敌还有我师傅推荐给我的一本关于UE4网络的PDF。 一、什么是Dedicated

Goulandis 3万+

什么是 AI Agent?它和直接调用大模型 API 有什么区别?

什么是 AI Agent?它和直接调用大模型 API 有什么区别?

我哎GIS博客 6479

[Java]JVM学习笔记

JVM学习笔记 在极客时间学习课程时,李智慧老师分享了关于新技术学习方法的经验,叫做“5-20-2”法。 解释一下,就是在学习一项新技术时: 要在5分钟之内了解他是解决了什么问题,相比竞品技术有什么优势; 在20分钟之内,了解这项技术在解决这些问题的时候用了哪些思路,哪些新颖方法; 在2个小时之内,试着做一些demo快速上手。 如果能做到这些,就对这项技术进行一个持续的深挖,如果解决不了这些问题,就及早收手,免得过多浪费时间。 为了试验上述方法的可行性,以JVM为切入点,我开始有意识的训练自己在短时

optimus 358

Vue2 - 最新详细实现接入天地图详细配置流程及示例代码教程,提供获取用户当前定位的城市名称及省市区数据、精准经纬度信息、IP属地定位、地图搜索标点等示例,解决天地图跨域报错/页面白屏/定位不准问题

vue2,nuxt2,天地图,使用教程,vue接入国家天地图,定位api,ip属地定位,获取用户当前位置数据,省市区,地图不显示,白屏,报错,vue2如何使用天地图,地图选点,cors跨域,白名单设置了还是不行,vue项目调用天地图api实现定位,Vue2中使用天地图,详细教程,天地图申请密钥key教程,经纬度,经纬度不准确,一直定位北京,定位在北京不准怎么办,nuxt项目天地图,网站,网页,h5页面,地图显示不全,获取当前定位,如何使用天地图,拿到客户ip地址定位城市名称,距离计算,实时搜索地址逆解析,天

🏆 前端领域优质创作者 5326

JVM学习笔记1

主要有五个阶段:(下面会重点讲解前三个阶段)

kwert666的博客 1648

Devexpress16.2.6破解工具

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

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

jvm学习笔记2

深入理解JVM的内存区域-0719 课前回顾 jdk-jre-jvm jvm是一个假设在操作系统之上的微型操作系统,需要依赖java自带的类库 跨语言、跨平台 java虚拟机主要是一种规范,主要有hotspot、j9、taobaovm、zing(土豪才能用) 从内存结构开始发散学习 线程私有区包括虚拟机栈、本地方法栈、程序计数器 虚拟机栈默认大小1M 运行java方法所需要的的数据指令存储在栈帧中 操作数栈存在的意义?类似于操作系统的缓存作用 直接内存,unsafe在

liusiping0902的博客 259

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

zabbix4.0监控JVM

Zabbix JVM

qq_26700739的博客 3241

Java学习笔记之JVM篇

Java学习笔记之JVM篇前言问:什么是JVM?问:JRE/JDK/JVM是什么关系?判断对象是否存活的算法问:如何回收对象垃圾收集算法(4种) 前言 这是JVM学习笔记,内容主要来自 周志明编写的《深入理解Java虚拟机 JVM高级特性与最佳实践》(第2版)一书,相当于是此书的读书笔记,还有一些内容引用自公众号内容 问:什么是JVM? 答:JVM是Java Virtual Machine(Jav...

qq_34882796的博客 872

Kotlin 2.0.0 有什么新功能

Kotlin 2.0.0 版本已经发布,新的Kotlin K2 编译器是稳定的!

a2965502228的博客 4452

JVM学习笔记2

bilibili-深入理解JVM 虚拟机 学习笔记 P6 _常量的本质含义与反编译及助记符详解(6) 虚拟机参数小笔记: -XX:+ 表示开启 option 选项 -XX:- 表示关闭 option 选项 -XX:= 表示 option 选项的值设置为 value 例如: -XX:+TraceClassLoading 开启打印加载的类列表,用于追踪类的加载信息,默认是不开启的; p...

晨猫 277

JVM基础篇学习笔记

JVM是Java虚拟机的缩写,本质上是运行在计算机上面的程序,作用是运行Java字节码文件。Tomcat使用了自定义类加载器来实现应用之间类的隔离,每一个应用会有一个独立的类加载器加载对于的类。ClassLoader的四个重要方法:// 每一个类加载器都会检查这个类有没有被加载过Class

无奇不有 不置可否的博客 1736

JVM学习笔记

JVM入门1 JVN入门探究2 JVM的体系研究2.1 JVM位置2.2 JVM的体系结构2. 类加载器2.1 理解类加载器:2.2 类加载器的执行顺序2.3 常量池的概念2.4 ClassLoader分类3 双亲委派机制4 Native方法4 程序计数器5 方法区6 栈(Stack)6.1 栈运行原理7 堆(Heap)7.1 新生区7.2 Sun HotSpot内存管理7.3 永久区(Perm)7.3 堆内存调优7.4 Dump内存快照沙箱安全机制 1 JVN入门探究 谈谈对JVM的理解?java8虚拟

CHAINQWE的博客 901

jvm学习笔记

个人jvm学习笔记

就很有趣的博客 1042

【学习笔记】jvm

3:类加载-初始化 加载过程 Loading 双亲委派,主要出于安全来考虑 LazyLoading 五种情况 –new get static put static invoke static指令,访问final变量除外 –java.lang.reflect对类进行反射调用时 –初始化子类的时候,父类首先初始化 –虚拟机启动时,被执行的主类必须初始化 –动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_putstatic

liu1251303815的博客 742

JVM学习笔记(一):JVM初探

1 来源 来源:《Java虚拟机 JVM故障诊断与性能优化》——葛一鸣 章节:第一章 本文是第一章的一些笔记整理。 2 Java里程碑 2.1 Java起源 1990年Sun公司决定开发一门新的程序语言——Oak,已经具备安全性、网络通信、面向对象、垃圾回收、多线程等特性,由于Oak已被注册,于是改名为Java。 2.2 JDK 1.0 1995年Sun发布了Java以及HotJava产品,1996年正式发布JDK 1.0,包括两部分: 运行环境:JRE,包括核心API,用户界面API,发布技术、JV

氷泠 475
上一篇: MySQL学习笔记2.0
下一篇: JVM学习笔记1.0
过河的小卒子
博客等级 码龄10年 39粉丝 112原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值