jvm的堆内存

堆空间的内存划分

这部分过多描述,直接上图
在这里插入图片描述
比例划分图上很明确了,一目了然;

新生代(年轻代):Eden区、from、to区;比例是8:1:1;新生代顾名思义就是存放新产生的对象的地方;老年代占用三分之二的内存空间;
打印对象空间分配的工具类 implementation ‘org.openjdk.jol:jol-core:0.14’
分代年龄: 一个对象的内存划分又包含对象头,对象体;对象头又分markword、类指针;markword又分:GC 分代年龄、锁状态标志、线程持有的锁、偏向线程ID 、偏向时间戳等。当前要说的重点是分带年龄(下图中的age),4bit位,其他的东西先不关注,需要说锁的时候详细说;在这里插入图片描述
这个age占了4bit位表示该数的范围 是 从二进制0000到1111;也就是从0~15;可能会有面试官问为什么分带年龄就到15?因为四位二进制最大数就是15;分带年龄是如何增长的呢?肯定是跟GC操作有关;在堆中存储的对象,经历过一次GC之后,依然存活没有被回收掉那么他的分代年龄就会 +1;这个内存分配下面具体说:

对象的分配过程

逃逸分析

1、方法逃逸:例如作为调用参数传递到其他方法中,例如下面

public static void main(String[] args) {
        //o只是创建了一个对象,除此之外并没有其他地方用到,此时就是栈上分配;当此方法运行完毕,栈帧销毁此对象也跟着销毁
        Object o = new Object();
    }

2、TLAB,全称Thread Local Allocation Buffer, 即:线程本地分配缓存。这是一块线程专用的内存分配区域。TLAB占用的是eden区的空间。在TLAB启用的情况下(默认开启),JVM会为每一个线程分配一块TLAB区域;是为了加速对象的分配。由于对象一般分配在堆上,而堆是线程共用的,因此可能会有多个线程在堆上申请空间,而每一次的对象分配都必须线程同步,会使分配的效率下降
3、大对象:直接在老年代生成,因为新生代的空间有限,如图在这里插入图片描述
简述:
(1)对象优先在Eden区分配
(2)空间分配担保
(3)大对象直接进入老年代
(4)长期存活的对象进入老年代(就看分带年龄,年龄7-15就进入老年代)
(5)动态对象年龄判断

GC

Minor GC/Young GC触发

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC,因为 Java 对象大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度也比较快。这一定义既清晰又易于理解
触发时机:
(1)、 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了
GC算法
Young GC 采用的是复制算法,一共分三个区,Eden、from、to区,最开始对象会在Eden区产生,执行一次垃圾回收;具体流程如下,一个对象的存储过程,一个→剪头代表一次GC操作,每次对象的分代年龄+1,大概7到15次之后,对象依然存活,那么就把该对象放入老年代
Eden→from→to→from→to→from→to→from→to→from→to→from→to→from→to→from→old
young GC采用的是 复制算法: 把Eden区+from区的需要存活的对象,整体复制到to区,然后删除Eden+from区的所有对象
或者把Eden+to区的复制到from区,然后删除Eden+to区;就这样来来回回,对象老了以后就弄到老年区

Full GC

出发时机
(1)调用System.gc时,系统建议执行Full GC,但是不必然执行
(2)老年代空间不足
(3)方法区空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
(5)由Eden区、From 区向 To 区复制时,对象大小大于To可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小
算法:
标记删除和标记整理
在这里插入图片描述
这个很好理解吧,内存区域是连续的,分配对象的过程也是连续的;一个挨着一个,但是由于垃圾回收,导致某些对象被回收掉了,所以对象之间产生了缝隙空间,所以需要重新整理,这样堆空间里就又有大片的连续空间了;这也是为什么在arrayList和hashMap之类的集合中,用到数组的地方,一旦需要扩容,就只能重新创建一个新的数组,旧的数组没法直接扩容;就是需要重新开辟一块更大的内存区域来放心的数组,而链表结构只是通过这真把每个对象连接起来,不需要移动对象位置,所以链表可以一直扩容。

Stop-The-World

Full GC同时作用于新生代和老年代。在垃圾回收过程中经常涉及到对对象的挪动(比如上文提到的对象在from区和to区之间的复制),进而导致需要对对象引用进行更新。为了保证引用更新的正确性,Java将暂停所有其他的线程,这种情况被称为“Stop-The-World”,导致系统全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互。Stop-The-World对系统性能存在影响,因此垃圾回收的一个原则是尽量减少“Stop-The-World”的时间。所以安卓在做性能优化的时候切记不要手动调用GC操作 我们要做的是理清关联关系,让不被需要的对象满足被GC回收的条件即可,当需要的时候系统就帮我们回收掉了,如果不满足条件调用一百次GC也不会达到我们想要的效果;
大部分垃圾回收算法都会STW只是具体看情况时间长短不同。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在macOS上,可以使用以下命令来查看JVM堆内存使用情况: 1. 打开终端应用程序。 2. 输入以下命令并按回车键运行:`jcmd <pid> VM.native_memory summary` 其中,`<pid>`是Java进程的进程ID,可以使用`jps`命令来查看Java进程的进程ID。 3. 终端将显示JVM的内存使用情况,包括堆内存和非堆内存的使用量。 请注意,这个命令需要在已经启动的Java进程上运行,并且需要有足够的权限来查看进程的内存信息。 #### 引用[.reference_title] - *1* [jvm堆内存初级调优](https://blog.csdn.net/weixin_42196915/article/details/100973119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [JVM内存限制和调整](https://blog.csdn.net/m0_67401382/article/details/126411355)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [JVM-内存管理](https://blog.csdn.net/u012804784/article/details/123124325)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值