JVM理论(四)运行时数据区--堆/方法区

news2025/1/11 4:19:18

(heap)

堆内存逻辑上分为三部分
  •  一个JVM实例只存在一个堆内存,JVM启动时创建堆区,通常情况下也是最大的内存空间,几乎所有的对象实例都要在堆中分配内存,所以堆也是垃圾回收的重点区域
  • 堆是被所有线程共享的,在堆里面也可以划分线程私有的缓冲区(TLAB-Thread Local Allocation Buffer)
  • 栈是JVM运行时的单位,堆是存储单位,当栈中方法结束,相关对象失去所有引用后,不会马上被移除堆空间,必须等到垃圾收集器执行的时候才会被移除
  • JVM中的java对象可以划分两类
    • 生命周期较短的瞬时对象,这类对象创建和消亡非常迅速(称为新生代)
    • 生命周期比较长,有时可能与JVM的生命周期一致(称为老年代)

新生代

新生代用来存放新生的对象,而且80%的对象都谁朝生夕死。由于频繁创建对象,所以新生代会频繁触发MinorGC 进行垃圾回收(默认内存大小是新生代:老年代=1:2);新生代又分为 Eden 区、Survivor From、SurvivorTo三个区域(三者内存大小默认是8:1:1)

Eden 区

Java 新对象的出生地.当 Eden 区内存不足时会触发 MinorGC/YGC,然后对新生代区进行一次垃圾回收

Survivor区

Survivor From用于存储上一次MinorGC的幸存者,作为下一次 GC 的被扫描者。而Survivor To则是为了保留下一次 MinorGC 过程中的幸存者

老年代

老年代主要存放应用程序中生命周期长的内存对象,老年代的对象比较稳定,所以不会频繁执行MajorGC/FGC

Java对象在JVM堆内存分配

 一般分配过程

  • 新new的对象首先进入Eden区,Eden区有大小限制;
  • 当Eden的空间不足存放新创建的对象时,JVM会进行垃圾回收(即Minor GC/YGC),将不再被引用的对象进行回收销毁,并将未被回收的对象放到Survivor From区;
  • 若再次触发Minor GC,在回收Eden区的同时,也会对Survivor From区进行回收,如果Survivor From中幸存下来的仍然没有回收,会同Eden未被回收的对象一同放到Survivor To区(此后作为Survivor From区),并清空Eden和Survivor From区;
  • 若再进行YGC,则会再次回收Eden和Survivor From区,将幸存对象放到Survivor To区
  • 正常来说,当Survivor 区的对象年龄达到默认15时,会晋升到老年代
  • 当老年代内存空间不足时,会触发Major GC/FGC进行老年代区域的垃圾回收
  • 若Major GC之后仍然无法存放新创建的对象,就会产生OOM异常(java.lang.OutOfMemoryError:Java Heap Spece)

特殊分配过程

  • 当新创建的对象无法存放在已经经过YGC的Eden区时,直接存放到老年代
  • 当经过YGC后Survivor 区也无法存放幸存的对象,也会直接放到老年代

总结

  • survivor区在复制后进行交换,谁空间为空谁就是survivor To;
  • 新生代会频繁进行垃圾回收,老年代很少进行垃圾回收,方法区/永久代几乎不进行垃圾回收

扩展

1.查看堆内存设置的参数情况

  • jps -l  => jstat -gc 进程id
  • -XX:+PrintGCDetails

2.空间分配担保

JDK7规定在发生YGC之前,虚拟机会检查老年代最大可用连续空间是否大于新生代所有对象的总空间,只要老年代的连续空间大于新生代对象总大小或者历次晋升的对象平均大小就会进行YGC,否则就进行FGC

3.逃逸分析(堆不再是分配对象存储的唯一选择)

不是;在JVM中,对象是在java堆中分配内存是普遍的常识,但是有一种特殊情况就是如果经过逃逸分析后发现,一个对象没有逃逸出方法的话,那么会被优先分配在栈上,这样就无需分配在堆上以至于垃圾回收,这也是最常见的堆外存储技术。

逃逸分析就是分析对象动态作用域

  • 当对象在方法中被定义后,只在方法内部使用,则认为没有发生逃逸,则可以被分配到栈上,随着方法执行结束,栈空间被移除。
  • 当对象在方法中被定义后,被外部方法所引用,则认为发生了逃逸,例如作为调用参数传递到其他地方使用。

所以在开发过程中,在方法内部定义的局部变量,不要在方法外定义;目前在JDK7后,Hotspot已经默认开启了逃逸分析。

方法区

堆栈方法区关系

概述 

  • 方法区也称为Non-heap非堆,目的就是和堆分开;所以方法区也可以看作一块独立于Java堆的内存空间
  • 方法区和堆一样,是各个线程共享的内存区域
  • 方法区在JVM启动被创建,在JVM关闭时释放
  • 方法区大小决定系统可以保存多少类,类过多可能导致方法区溢出,虚拟机会报内存溢出错误,如:java.lang.OutOfMemoryError:PermGen/Metaspace
  • 方法区演进:JVM规范定义了方法区,针对Hotspot的实现,Jdk7以及以前,方法区被称为永久代;JDK8开始,改用和JRocket,J9一样在本地内存中实现的元空间来代替永久代;
  • 方法区的垃圾回收的主要内容:常量池中废弃的常量和不再使用的类型信息

内部结构

JVM虚拟机规范中规定方法区中用于存储被JVM虚拟机加载的类型信息、常量、静态变量、JIT编译后的代码缓存

对于每个加载的类型(类、接口、枚举、注解),JVM必须在方法区中存储以下类型信息、域信息、方法信息

  • 类型信息

    • 类型的完整有效名称(包名.类名);
    • 类型的直接父类的完整有效名;
    • 类型的修饰符(Public,abstract,final);
    • 类型直接接口的一个有序列表
  • 域(Field)/属性信息

    • 域名称
    • 域类型
    • 域修饰符(Public、private、protected等)
  • 方法信息

    • 方法名称

    • 方法返回类型

    • 方法参数数量和类型

    • 方法修饰符

    • 方法字节码、操作数栈、局部变量表及大小

    • 异常表

运行时常量池

首先被编译后的class字节码文件中存在常量池的引用,当字节码被加载到内存的方法区后,被称为运行时常量池,它的作用就是将经常使用到的数据存储在常量池,方便取用,动态链接会使用到运行时常量池,其中存储内容包括

  • 数量值
  • 字符串值
  • 类引用
  • 字段引用
  • 方法引用

方法区实现的演进过程

  • JDK1.6及以前:存在永久代,静态变量存放在永久代之中
  • JDK1.7: 有永久代,但逐步"去永久代",其中字符串常量池和静态变量已经从永久代移除,并将其保存在堆中
    • 字符串常量池StringTable为什么要从方法区中调整到堆中?
      JDK7将StringTable放到了堆空间中,因为永久代的回收效率很低;只有在老年代空间不足或者永久代空间不足时发生FGC时才会回收StringTable,就导致StringTable回收效率低,而我们开发中会有大量的字符串被创建,回收效率低最终导致永久代内存不足,而放到堆里则能及时回收内存
  • JDK1.8及以后:无永久代,元空间代替永久代(元空间本质和永久代类似,都是JVM规范中方法区的实现,区别在于元空间不在虚拟机设置的内存中,而是使用本地内存),且字符串常量池和静态变量仍在堆中

常见的JVM参数设置

-X是JVM的运行参数

-Xms:设置堆内存初始大小(新生代+老年代),默认电脑物理内存/64

-Xmx:设置堆内存最大内存大小,默认电脑物理内存/4

-XX:SurvivorRation=8,作用是将新生代的Eden与另两个Survivor区域占比比例设置为8:1:1

-Xmn:设置新生代空间大小(一般优先级高于NewRatio,但通常开发中不作设置)

-XX:NewRatio=2,堆内存中年轻代:老年代=1:2(开发中通常不作调整)

-XX: MaxTenuringThreshold=<N> 设置新生代垃圾的最大年龄,N表示年龄,默认15  

-XX:+PrintFlagsInitial     启用查看所有参数的默认初始值

-XX:+PrintFlagsFinal       启用查看所有参数的最终值

-XX:+PrintGCDetails        输出详细的GC处理日志

-XX:HandlePromotionFailure 是否设置空间分配担保

-XX: PermSize 用于JDK8以前设置永久代初始分配空间,默认20.75M
-XX: MaxPermSize 用于JDK8以前设置永久代最大可分配空间,32位默认64M,64位默认82M

-XX: MetaspaceSize 用于JDK8及以后设置永久代初始分配空间,默认21M(实际开发中我们会设置一个值,并且初始最大值是相同的)
-XX: MaxMetaspaceSize 用于JDK8及以后设置元空间最大空间,默认-1,表示无限制(实际开发中我们会设置一个值,并且初始最大值是相同的)

常见问题

堆空间大小设置时,为何-Xms和-Xmx两个参数要设置相同的值?

目的是为了能够在GC清理完堆内存后不需要重新分隔计算堆区大小,减少系统压力从而提高性能 

为什么需要把Java堆分代,不分带就不能正常工作了吗?

完全可以不分代,分代的唯一理由就是优化GC性能;
如果没有分代,所有的对象都在一起,GC的时候需要分析哪些对象没用,此时就需要对堆的所有区域进行扫描,占用资源且时间长;而我们知道,其实很多对象都是朝生夕死的,
如果分代的话,把新创建的对象放到一个区域,当GC时会首先对此区域进行回收,释放空间。而长期存活的对象放到另一个区域,且不会频繁进行回收,这样各个区域各司其职,提高资源利用.

为什么在堆里面设置线程私有的缓冲区TLAB?

首先堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据,所以会产生线程安全问题.为了避免多个线程操作同一地址,需要使用加锁等机制,但加锁又会影响分配进度;
所以出现了TLAB,JVM会为每个线程分配一个私有缓存区域TLAB,它被分配在Eden区域;这样多线程在运行时会避免线程安全问题;

  • OpenJDK目前都提供了对TLAB的设计
  • TLAB空间内存非常小,仅占整个Eden空间的1%;
  • 不是所有对象都可以在TLAB中成功分配内存,一旦分配失败,JVM就会尝试通过使用加锁机制确保操作原子性,从而在Eden中分配内存

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/756903.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

肝!熬夜到天明,阿里顶配级 Spring Security 笔记

Spring Security Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是 Spring 生态系统中的一员&#xff0c;因此它伴随着整个 Spring 生态系统不断修正、升级&#xff0c;在 spring boot 项目中加入 springsecurit…

Ubuntu下安装Miniconda

下载 到根据自己本地python版本到官网下载 https://docs.conda.io/en/latest/miniconda.html#linux-installers 我本地是python3.8 然后上传到Ubuntu服务器上&#xff0c;或者直接使用wget下载&#xff1a; wget https://repo.anaconda.com/miniconda/Miniconda3-py38_23.5…

WebSocket理论和实战

一 WebSocket理论 1.1 什么是http请求 http链接分为短链接、长链接&#xff0c;短链接是每次请求都要三次握手才能发送自己的信息。即每一个request对应一个response。长链接是在一定的期限内保持链接&#xff08;但是是单向的&#xff0c;只能从客户端向服务端发消息&#x…

单例模式、指令重排序、锁、有序性

今天在回顾单例模式时&#xff0c;我们都知道懒汉式单例中有一种叫做双重检查锁的单例模式。 我们来看下下面的代码有没有问题&#xff1a; 这段代码我们可以看到&#xff0c;即优化了性能&#xff0c;在多线程情况下&#xff0c;如果实例不为空了&#xff0c;则直接返回了。…

1766_perl实现readlines功能

全部学习汇总&#xff1a; GreyZhang/perl_basic: some perl basic learning notes. (github.com) 近段时间写一个Perl程序&#xff0c;中间反反复复用到了文件的读写。虽说是用Perl的基本功能实现读写非常简单&#xff0c;但是写的过程中我不止一次在想Python以及MATLAB的功能…

华为OD机试真题 Java 实现【评论转换输出】【2023 B卷 100分】,附详细解题思路

目录 专栏导读一、题目描述在这里插入图片描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A…

什么是元学习?外循环和内循环?支持集和查询集?

一、前言 元学习近几年也算是一个比较热门的研究方向&#xff0c;大部分被用来解决低资源少样本零样本学习的任务场景中。 那么为什么元学习可以提升低资源少样本的学习效果呢&#xff1f;活着说元学习到底是一个什么阳的算法呢&#xff1f; 这里做一个简单的概念阐述。元学…

echart之map地图图表使用教程

本文以echarts展示成都地图为例子。 echarts map &#xff08;echarts地图&#xff09;使用教程 效果展示准备阶段获取地图geojson数据安装echarts 开始绘制容器准备js代码 补充事项vue3.0 用ref定义echarts报错toRaw、markRaw 扩展 地图隐藏南海诸岛地图显示提示框地图实现下钻…

Vue项目的启动

前言&#xff1a; 由于最近开始实习&#xff0c;负责人上来就给我丢一个前端vue项目和后端文件&#xff0c;让我在本机完成部署&#xff0c;由于之前学的基本上都是后端相关知识&#xff0c;很少有了解到前端的东西&#xff0c;因此在这里将自己部署Vue项目时遇到的问题和解决过…

编译libtiff库给IOS平台用

打开libtiff官方网 : libtiff / libtiff GitLab 克隆: git clone --recursive https://gitlab.com/libtiff/libtiff.git 克隆成功并打开libtiff目录,发现有autogen.sh 与CMakeLists.txt所以可生成Configure程序来配置并编译,也可直接使用CMake-GUI来配置编译,选择其中一种 …

远程会诊如何实现?

比如&#xff1a;医生遇到复杂病情需要求助院外专家远程会诊过程中&#xff0c;需要将电脑中的病人资料给院外专家看&#xff0c;同时确保医院电脑和网络系统绝对安全&#xff0c;电脑不允许安装任何外部软件&#xff0c;不能被外人控制和操作&#xff0c;外部设备不能接入医院…

【Java技术专题】「攻破技术盲区」带你攻破你很可能存在的Java技术盲点之技术功底指南(鲜为人知的技术)

带你攻破你很可能存在的Java技术盲点之技术功底指南 基本类型的包装类技术盲点&#xff1a;基本类型的比较技术盲点&#xff1a;字符串内部化&#xff08;string interning&#xff09;字符串内部化的示例 技术盲点&#xff1a;类型缓存机制&#xff08;空间换时间&#xff09;…

微信小程序border-radius不圆滑

border-radius可以设置&#xff1a;百分比或者像素值 1.使用像素值比较圆滑 2.使用百分比不够圆滑

习题1.25

对吗?实践出真知,运行看看。代码如下。 (defn square [x] (* x x))(defn fast-expt[b n](println "call iter" n)(cond (= 1 n) b(= 2 n) (square b)(even? n) (square (fast-expt b (/ n 2))):else (* b (fast-expt b (- n 1)))))(defn expmod [base exp m](mod…

pytest 结合logging输出日志保存至文件

API_log.py import loggingclass loger():def logering(self):# 创建logger对象logger logging.getLogger(test_logger)# 设置日志等级logger.setLevel(logging.DEBUG)# 追加写入文件a &#xff0c;设置utf-8编码防止中文写入乱码test_log logging.FileHandler(test.log, a,…

Java:基于JDBC数据连接池方式同步第三方数据库表信息数据

前言 最近遇到一个需求就是要拉取第三方的数据信息&#xff0c;但是第三方那边又没有对外暴露对接接口&#xff0c;只给出了具体的数据库连接信息和具体表信息基于第三方给出的有效信息&#xff0c;我采取了用 JDBC 传统的方式去进行数据拉取注意&#xff1a;前置条件两端的网…

收费站对讲广播系统方案

收费站对讲广播系统方案 收费站对讲广播系统是一种用于收费站内部通信和广播传输的系统。它能够实现不同收费站点之间的语音通信和广播&#xff0c;以便快速、准确地传达信息和指令。该系统通常由以下几个核心组件组成&#xff1a;1. 主控台&#xff1a;主控台是系统的中心控制…

cocos shader在编辑器正常,浏览器上不显示

问题出在需要将图片的package属性取消勾选。如果用的单色精灵&#xff0c;那么可以将系统的白色图片复制一份再取消勾选。 相关链接&#xff1a; shader在浏览器上不显示 - Creator 2.x - Cocos中文社区

Redis高级篇(一)

分布式缓存 -- 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题&#xff1a; 1.Redis持久化 Redis有两种持久化方案&#xff1a;RDB持久化、AOF持久化 1.1.RDB持久化 什么是RDB持久化 RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&am…

第一章 JavaScript --下

第一章 JavaScript --下 2.5.6 DOM操作 由于实际开发时基本上都是使用JavaScript的各种框架来操作&#xff0c;而框架中的操作方式和我们现在看到的原生操作完全不同&#xff0c;所以下面罗列的API仅供参考&#xff0c;不做要求。 2.5.6.1 在整个文档范围内查询元素节点 功…