JVM-堆

article/2025/9/25 12:36:24

文章目录

    • 堆,是运行是数据区的一部分
    • 堆内存分区:
      • JAVA堆区细分:
    • 设置堆内存大小与OOM
      • 设置堆空间大小
    • OOM Outof Memory Error 举例!!!
    • 图解对象分配过程
    • Minor GC、Major GC、Full GC
      • 年轻代 GC(Minor GC)触发机制
      • 老年代 GC(MajorGC)触发机制
    • 堆空间分代思想:
    • TLAB:Thread Local Allocation Buffer
    • 堆小结:

堆,是运行是数据区的一部分

在这里插入图片描述
一个进程对应一个JVM实例,一个JVM实例只有一个运行时数据区,只有一个方法区和堆,一个进程的多个线程共享方法区和堆。
1、一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域。
2、Java堆区在JVM启动的时候即被创建,其空间大小也就确定了,堆是JVM管理的最大一块内存空间,并且堆内存的大小是可以调节的。
3、所有的线程共享Java堆,要考虑线程的安全问题,并发性就差,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB),提高并发性。
4、数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置。
5、在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。也就是触发了GC的时候,才会进行回收。
如果栈里面对象引用一出栈,堆里面的对象立马GC,会造成GC的频率特别高,会影响用户线程的执行
6、堆,是GC(Garbage Collection,垃圾收集器)执行垃圾回收的重点区域。
虚拟机栈没有GC,只有入栈和出栈
在这里插入图片描述

堆内存分区:

在这里插入图片描述
JAVA7及之前 新生区,养老区,永久区
JAVA8及之后 新生区,养老区,元空间

存储在JVM中的JAVA对象
1、:生存周期较短的瞬时对象,创建和消亡都迅速(生命周期短的,及时回收即可)
2、生命周期长(极端情况下与JVM生命周期保持一致)

JAVA堆区细分:

1、年轻代(YoungGen):
aEden空间(伊甸区)
b:from区(Survivor0)
c:to区(Survivor1)
2、老年代(oldGen)
在这里插入图片描述
比例:
1、默认-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的1/3
2、可以修改-XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的1/5
在这里插入图片描述
几乎所有的Java对象都是在Eden区被new出来的。绝大部分的Java对象的销毁都在新生代进行了(有些大的对象在Eden区无法存储时候,将直接进入老年代

新生代的对象默认生命周期超过 15 ,就会去养老区养老

设置堆内存大小与OOM

设置堆空间大小

1、Java堆区用于存储Java对象实例,那么堆的大小在JVM启动时就已经设定好了,大家可以通过选项"-Xms"和"-Xmx"来进行设置。
-Xms用于表示堆区的起始内存,等价于-XX:InitialHeapSize
-Xmx则用于表示堆区的最大内存,等价于-XX:MaxHeapSize
2、一旦堆区中的内存大小超过“-Xmx"所指定的最大内存时,将会抛出OutofMemoryError异常。
3、通常会将-Xms和-Xmx两个参数配置相同的值,其目的是为了能够在Java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能。
4、默认情况下:
初始内存大小:物理电脑内存大小/64
最大内存大小:物理电脑内存大小/4
/**

    1. 设置堆空间大小的参数
  • -Xms 用来设置堆空间(年轻代+老年代)的初始内存大小
  •  -X 是jvm的运行参数
    
  •  ms 是memory start
    
  • -Xmx 用来设置堆空间(年轻代+老年代)的最大内存大小
    1. 默认堆空间的大小
  • 初始内存大小:物理电脑内存大小 / 64
  • 最大内存大小:物理电脑内存大小 / 4
    1. 手动设置:-Xms600m -Xmx600m
  • 开发中建议将初始堆内存和最大的堆内存设置成相同的值。
    因为如果不一样,空间不够要扩容,空闲时候要释放,频繁的扩容和释放会造成系统的压力
    

*/

OOM Outof Memory Error 举例!!!

/*** -Xms600m -Xmx600m*/
public class OOMTest {public static void main(String[] args) {ArrayList<Picture> list = new ArrayList<>();while(true){try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}list.add(new Picture(new Random().nextInt(1024 * 1024)));}}
}class Picture{private byte[] pixels;public Picture(int length) {this.pixels = new byte[length];}
}

在这里插入图片描述
监控堆内存变化:Old 区域一点一点在变大,直到最后一次垃圾回收器无法回收垃圾时,堆内存被撑爆,抛出 OutOfMemoryError 错误
堆内存变化图
分析原因:大对象导致堆内存溢出

图解对象分配过程

1、我们创建的对象,一般都是存放在Eden区的,当我们Eden区满了后,就会触发GC操作,一般被称为 YGC / Minor GC操作。
Eden和S0、S1的比例是8:1:1,只有Eden满了才出发YGC,S0满了不会触发YGC,但是触发YGC时候会把Eden和S0一起回收。
在这里插入图片描述
2、当我们进行一次垃圾收集后,红色的对象将会被回收(不再被使用,没有引用指向他),而绿色的还被使用着,存放在S0(Survivor From)区。
同时我们给每个对象设置了一个年龄计数器,经过一次回收后还存在的对象,将其年龄加 1。
3、同时Eden区继续存放对象,当Eden区再次存满的时候,又会触发一个MinorGC操作,此时GC将会把 Eden和Survivor From中的对象进行一次垃圾收集,
把存活的对象放到 Survivor To区,同时让存活的对象年龄 + 1,现在S1是From区,S0是To区(经过一次MinorGC后谁空谁就是To区)。
在这里插入图片描述
4、我们继续不断的进行对象生成和垃圾回收,当Survivor中的对象的年龄达到15的时候,将会触发一次 Promotion 晋升的操作,也就是将年轻代中的对象晋升到老年代中.
可以设置新生区进入养老区的年龄限制,设置 JVM 参数:-XX:MaxTenuringThreshold=N 进行设置
在这里插入图片描述
在养老区,相对悠闲。当养老区内存不足时,再次触发GC:Major GC,进行养老区的内存清理
若养老区执行了Major GC之后,发现依然无法进行对象的保存,就会产生OOM异常。

在这里插入图片描述
总结:
1、针对幸存者s0, s1区的总结:交换之后,谁空谁是to.
2、关于垃圾回收:频繁在新生代收集,很少在老年代收集,几乎不在永久区/元空间收集
永久区/元空间是方法区的落地实现

Minor GC、Major GC、Full GC

1、我们都知道,JVM的调优的一个环节,也就是垃圾收集,我们需要尽量的避免垃圾回收,因为在垃圾回收的过程中,容易出现STW(Stop the World)的问题,会停掉用户线程,而 Major GC 和 Full GC出现STW的时间,是Minor GC的10倍以上
2、JVM在进行GC时,并非每次都对上面三个内存区域(新生代、老年代、方法区)一起回收的,大部分时候回收的都是指新生代。
针对Hotspot VM的实现,它里面的GC按照回收区域又分为两大种类型:一种是部分收集(Partial GC),一种是整堆收集(FullGC)
部分收集:
不是完整收集整个Java堆的垃圾收集。其中又分为:
1、新生代收集(Minor GC/Young GC):只是新生代的垃圾收集
2、老年代收集: (Major GC/Old GC):只是老年代的圾收集。
注意,很多时候Major GC会和Full GC混淆使用,需要具体分辨是老年代回收还是整堆回收。
整堆收集(Full GC):
收集整个java堆(新生代和老年代)和方法区的垃圾收集。

年轻代 GC(Minor GC)触发机制

1、当年轻代空间不足时,就会触发Minor GC,这里的年轻代满指的是Eden代满,Survivor满不会引发GC。(每次Minor GC会清理年轻代的内存)
2、因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。这一定义既清晰又易于理解。
3、Minor GC会引发STW(Stop The Word),暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行,一般回收速度也比较快,所以对用户线程影响比较小,
影响较大的是老年代GC,STW时间较长。

老年代 GC(MajorGC)触发机制

1、指发生在老年代的GC,对象从老年代消失时,我们说 “Major Gc” 或 “Full GC” 发生了
2、出现了MajorGc,经常会伴随至少一次的Minor GC
但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行MajorGC的策略选择过程
也就是在老年代空间不足时,会先尝试触发Minor GC,如果之后空间还不足,则触发Major GC
3、Major GC的速度一般会比Minor GC慢10倍以上,STW的时间更长,如果Major GC后,内存还不足,就报OOM了

堆空间分代思想:

分代的唯一理由就是优化GC性能
1、如果没有分代,那所有的对象都在一块,就如同把一个学校的人都关在一个教室。GC的时候要找到哪些对象没用,这样就会对堆的所有区域进行扫描。
2、而很多对象都是朝生夕死的,如果分代的话,把新创建的对象放到某一地方,当GC的时候先把这块存储“朝生夕死”对象的区域进行回收,这样就会腾出很大的空间出来。

Minor GC会引发STW,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行,一般回收速度也比较快,所以对用户线程影响比较小,
影响较大的是老年代GC,STW时间较长,对GC的优化减少GC出现的频率

TLAB:Thread Local Allocation Buffer

问题:堆空间都是共享的么?
不一定,因为还有TLAB这个概念,在堆中划分出一块区域,为每个线程所独占

为什么有TLAB(Thread Local Allocation Buffer)?
1、TLAB:Thread Local Allocation Buffer,也就是为每个线程单独分配了一个缓冲区
2、堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据
3、由于对象实例的创建在JVM中非常频繁,因此在并发环境下从堆区中划分内存空间是线程不安全的,
为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度。

在这里插入图片描述

1、尽管不是所有的对象实例都能够在TLAB中成功分配内存,但JVM确实是将TLAB作为内存分配的首选。
2、默认情况下,TLAB空间的内存非常小,仅占有整个Eden空间的1%
3、一旦对象在TLAB空间分配内存失败时,JVM就会尝试着通过使用加锁机制确保数据操作的原子性,从而直接在Eden空间中分配内存。

堆小结:

1、老年代放置长生命周期的对象,通常都是从Survivor区域筛选拷贝过来的Java对象。
2、JVM为每个线程分配了一个私有缓存区域TLAB,将TLAB作为内存分配的首选
如果对象较大,无法分配在 TLAB 上,则JVM会试图直接分配在Eden其他位置上;
如果对象太大,完全无法在新生代找到足够长的连续空闲空间,JVM就会直接分配到老年代。
3、当GC只发生在年轻代中,回收年轻代对象的行为被称为Minor GC。当GC发生在老年代时则被称为Major GC或者Full GC。
一般的,Minor GC的发生频率要比Major GC高很多,即老年代中垃圾回收发生的频率将大大低于年轻代。
在这里插入图片描述


http://chatgpt.dhexx.cn/article/e7Kc4E9G.shtml

相关文章

jvm堆大小的设置

问题引入&#xff1a; -Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio3&#xff0c;,其最小内存值和Survivor区总大小分别是&#xff08;10240m 2048m&#xff09;&#xff1b; 解析&#xff1a; -Xmx&#xff1a;最大堆大小 -Xms&#xff1a;初始堆大小 -Xmn:年轻…

如何修改java中堆、栈空间的默认大小

1、修改堆、栈空间大小的命令 在命令行中输入java -X可以得到设置java堆大小和栈大小的命令 2、修改java运行时的堆和栈空间 进入界面后 按AltV 3、检验堆空间修改 3.1 测试类 public class StackTest {public static void main(String[] args) {//返回Java虚拟机中的堆内存…

java 堆设置

Young&#xff1a;主要是用来存放新生的对象。&#xff08;Eden、survivorSpaces(from、To)&#xff09; Old&#xff1a;主要存放应用程序中生命周期长的内存对象。 Permanent&#xff1a;是指内存的永久保存区域&#xff0c;主要存放Class和Meta的信息,Class在被 Load的时候…

Java堆内存设置

堆内存设置 原理 JVM堆内存分为2块&#xff1a;永久空间和堆空间。 永久即持久代&#xff08;Permanent Generation&#xff09;&#xff0c;主要存放的是Java类定义信息&#xff0c;与垃圾收集器要收集的Java对象关系不大。Heap {Old NEW {Eden&#xff0c;from&#xff0…

OBEX(一)

一、概述 1、OBEX v2.0&#xff08;v2.0版本开始OBEX直接在L2CAP上传输&#xff0c;v2.0版本以前OBEX在RFCOMM上传输&#xff09; 2、OBEX即Object Exchange Protocol&#xff0c;对象交换协议 3、OBEX协议是典型的client/server request-response模型 4、OBEX v2.0蓝牙协议…

利用docker部署oxidized网络设备备份系统

随着网络设备的增多,通过人手备份网络设备倍感压力,而且效率低。有编程基础的人可能会通过Python的parimiko 或者netmiko 连接到设备操作 把文件通过ftp 上传到FTP服务器, 在通过定时任务,定期自动备份。这个应该是现阶段主流非人民币网络玩家的最优解决方案。 今天我们来看看…

网络自动化运维第一篇 自动化备份网络配置

网络设备厂商众多&#xff0c;各种安全厂商&#xff0c;网络厂商&#xff0c;负载均衡厂商&#xff0c;如果想实现自动化备份配置&#xff0c;可以自己写python脚本。如果网络设备厂商多&#xff0c;自己写python 非常耗费时间精力。偶然在网上发现了oxidized 非常好用&#xf…

.odex文件的反编译

0x00 问题呈现 在分析某手机自带应用时&#xff0c;为了在JEB中反编译&#xff0c;将其adb pull到了电脑上。解压后发现如下文件&#xff1a; APK解压目录列表 惊奇的发现该APK包中没有dex文件&#xff0c;一开始特别疑惑没有dex文件&#xff0c;也就是没有代码&#xff0c;那…

ZeroDivisionError: integer division or modulo by zero

这里的错误就是由于数据集太小。 # 2. Split into train / validation partitionsn_val int(len(dataset) * val_percent)n_train len(dataset) - n_val#我这里是刚好有10张数据集然后其中一张被拆分为验证集导致训练集太小&#xff0c;从而报错。

反编译odex

需要工具&#xff1a; 1、baksmali-x.x.x.jar2、smali-x.x.x.jar工具下载&#xff1a;https://bitbucket.org/JesusFreke/smali/downloads/ 步骤&#xff1a; 1、odex转smali&#xff1a; java -jar “D:\google\tool\mony_tool\baksmali-2.2.1.jar” deodex SystemUI.odex -…

ZeroDivisionError:Integer division or modulo by zero

docker环境下&#xff0c;多GPU训练 方式&#xff1a;采用nvidia-docker创建容器 另&#xff1a; 在用sudo无法解决sh文件的pemission denied问题时&#xff0c;采用bash替代sudo

deactive(Deactive breakpoint)

deactive怎么译&#xff1f; de-active 原指吊销, 计算机的专用词叫 "去活". 多指停止某指令.吊销&#xff0c;不激活&#xff0c;关闭 三星bc01指令代码 三星手机总复位&#xff0c;在待机状态下输入*2767*3855#需要专门的智能仪器才可以解开手机密码忘记了 一般普…

Oxidized-20180912-docker 版本的网络设备备份系统

Problem Oxidized 非常好用&#xff0c;基本兼容所有网络设备的备份&#xff0c;但是有一个小小小小的问题&#xff0c;就是在 Linux 环境下&#xff0c;默认安装的 Ruby 版本问题为其在离线情况下的安装增添了很多的麻烦和限制。 于是轻量级的 docker 成了不二的选择。 &am…

Oxidized-最好用的网络设备备份系统(三)-双机自动备份

oxidized备份网络配置默认路径为 /root/.config/oxidized/group group分别是不同设备分组 group1 group2 group3 group4 双机自动备份思路: 制作将需要备份的数据先备份到back/bak目录下,再通过打包gz格式放到backup目录下,然后通过远程传输,上传到备份服务器的/usr/…

cas:27025-41-8 Glutathione oxidized氧化型谷胱甘肽 活性氧抑制剂

cas:27025-41-8 Glutathione oxidized氧化型谷胱甘肽 活性氧抑制剂 中文名称&#xff1a;氧化型谷胱甘肽 英文名称&#xff1a;Glutathione oxidized 分子量&#xff1a;612.63 性状&#xff1a;Solid 分子式&#xff1a;C20H32N6O12S2 cas:27025-41-8 别称&#xff1a;…

Oxidized-最好用的网络设备备份系统(二)

上文回顾 书接上文, 看完上篇文章的同学相信大家对这个”oxidized” 有了初步的了解, 有同学对config 配置有些疑惑 我这里简单介绍一下。 --- username: username : 用户名 这个参数不用改,会从router.db读取. password: password : 密码 这个参数也不用改,会从router.db…

整理了一下oxidized+mysql+gitlab,感觉很好用,做个记录

安装oxidized 安装ruby yum install centos-release-scl yum install rh-ruby23 rh-ruby23-ruby-devel scl enable rh-ruby23 bash 安装依赖关系 yum install make cmake sqlite-devel openssl-devel libssh2-devel ruby gcc ruby-devel libicu-devel gcc-c 安装oxidized gem…

docker oxidized时区问题,时间显示不是北京时间问题的解决办法

问题描述&#xff1a;oxidized web界面时间显示&#xff0c;默认显示UTC时间&#xff0c;为北京时间-8个小时 问题原因&#xff1a;ruby语言的时间直接获取的UTC时间 出现版本&#xff1a;oxidized 0.28.0 问题解决&#xff1a; docker exec -it oxidized /bin/bashvim /var/l…

网络设备配置备份-Oxidized

背景&#xff1a;网络设备如何备份&#xff1f;关于这个问题笔者尝试了多种&#xff0c;比如&#xff1a;通告FTP下载配置文件&#xff0c;通过ssh软件登录设备记录当前配置等&#xff0c;在一次偶然的机会中找到了Oxidized&#xff08;开源软件&#xff09;&#xff0c;可以增…

Oxidized 网络设备自动备份系统搭建

文章目录 前言一、oxidized是什么&#xff1f;二、oxidized搭建1.环境准备2.安装步骤3.配置文件4.router.db 文件规范5.运行6.Nginx验证登录 三&#xff0c;踩坑总结 前言 传统的网络设备备份通常都是人工登录进行手动操作&#xff0c;随着管理的网络设备越来越多&#xff0c;…