JVM分代模型:年轻代,老年代,永久代

大部分对象是朝生夕灭

前面我们说到的Manager对象,经过一系列流程很快就被消灭掉了,这也是Java代码中绝大多数的情况,存活周期很短。

少数对象是长期存活的

public class Play{

    private static Manager manager = new Manager();

    public static void main(String[] args) {
        while(true) {
            loadFile();
            Thread.sleep(1000);
        }
    }

    private static void loadFile() {
        manager.load();
    }

}

这一段代码里面。main方法中一个wile循环一直在调用load方法,其一直会驻留在Java堆内存中,是不会被垃圾回收掉的。

JVM分代模型:年轻代和老年代

年轻代:创建和使用完之后立马就要回收的对象放在里面

老年代:创建之后需要一直长期存在的对象放在里面

为什么需要区分年轻代和老年代?

这和垃圾回收有关,对于年轻代的对象,他们的特点是创建之后很快就会被回收,使用需要一种垃圾回收算法

而老年代对象,他们的特点是需要长期存在,所有需要另一种垃圾回收算法,因此要分为两个不同的区域存放对象

什么是永久代?

JVM里的永久代也就是我们之前说的方法区,永久代也就是存放一些类信息的。

你的对象在JVM内存中如何分配?如何流转?

大部分正常对象都优先在年轻代分配内存

首先我们需要知道:大部分正常对象,都优先在年轻代分配内存

到底什么情况下会触发垃圾回收?

前面我们说明当"Manager"实例对象没有任何局部变量引用他,这时候就一定会发生垃圾回收吗?

不是这样的,垃圾回收有自己的触发条件

当我们代码中new了很多N对象,导致Java堆内存中囤积了大量对象,这些对象之前被人引用过,但是因为各种原因现在都没有引用。

现在我们的新生代预先分配的内存空间几乎都被占满了,此时我们的代码如果还要继续执行,怎么办?

这个时候就会触发一次新生代内存空间的垃圾回收,也叫做"Young GC",将年轻代中没有人引用的对象回收掉。

长期存活的对象会躲过多次垃圾回收

在JVM中有这么一个规定,如果一个实例对象在新生代中,成功度过了15次垃圾回收之后,还没有被回收掉,说明其已经15岁了,这时候其就会被移动到老年代中。

老年代会被回收吗?

这个也是肯定的,当程序运行的时候,老年代的对象不被人引用了,也需要垃圾回收,在老年代满了的时候是不是也需要这个垃圾回收。

这里我们只需要先了解一下这个概念,后面我们会去深入讨论他。

线上系统部署JVM如何设置大小?

JVM内存相关的几个核心参数

-Xms:Java堆内存的大小

-Xmx:Java堆内存的最大大小

-Xmn:Java堆内存中的新生代大小,扣除新生代剩下的就是老年代的内存大小

-XX:PermSize:永久代大小

-XX:MaxPermSize:永久代最大大小

-Xss:每个线程的栈内存大小

如何在启动系统的时候设置JVM参数?

在IDEA里面

命令行启动程序:

java -Xms512M -Xmx512M -Xmn256M -Xss1M -XX:PermSize=128M -XX:MaxPermSize=128M -jar app.jar

每日百万交易的支付系统,如何设置JVM堆内存大小

支付系统引入

支付系统的背景

支付的核心业务流程

系统的压力在哪里?

我们系统的最核心的流程就是用户在发起支付请求的时候,会生成一个支付订单,支付订单需要清楚记录里面的各类信息。

在JVM的角度上来看,也就是JVM每天会创建上百万个支付对象。

而JVM的压力就是内存中频繁创建和销毁100万个支付订单,这里面就涉及以下问题:

  • 我们支付系统需要部署多少台机器?
  • 每台机器上启动JVM需要分配多大的堆内存空间?
  • 每台机器上启动都会JVM需要分配多大的堆内存空间?
  • 给JVM多大的内存空间才能保证可以支持这么多的支付订单在内存里的创建,而不会导致内存不够直接崩溃?

支付系统每秒钟需要处理多少订单?

我们要解决线上系统最核心的一个参数,JVM堆内存大小的合理设置,也就需要计算我们系统要处理多少支付订单

假设每天100万支付订单,一般交易行为都发生在中午或晚上,每天高峰期几个小时,大概就是每秒100笔订单左右

人工我们部署3台机器,每台机器每秒大概处理30笔订单

每个订单耗时多久?

假设一个支付订单创建需要1s时间,也就是每台机器1s钟收到30笔支付订单请求,然后JVM的新生代里面创建30个支付订单对象,做数据库写入操作,1s后,30个支付订单处理完毕,这些支付订单对象就被回收了,这些订单在JVM新生代里面就没人引用,成为垃圾对象了

每个订单要多少内存空间?

Integer变量是4个字节,Long是8个字节

一般来说一个支付订单会有20个左右的实例变量,大概就是一个对象几百字节左右,我们就算其为500字节内存空间

每秒发起支付请求对内存的占用

创建30个支付订单,30*500字节=15000字节,大概就是15kb,其实非常小

支付系统运行起来分析

支付系统运行起来,这样的创建对象销毁对象,不到一会就可能占据了几百MB,将新生代占满,这时就会发生Young GC

对支付系统内存占用进行预估

支付系统只是其中一部分,肯定会有还有其他系统存在,大概就是把之前计算扩大10~20倍

每秒在栈内存局部变量引用的对象大致在几百KB~1MB之间

支付系统的JVM堆内存该怎么设置?

这种线上的业务系统一般部署在2核4G,或者4核8G的机器上

如果是2核4G都会机器,因为机器本身需要一定空间,所以JVM进程最多2G内存

这2G内存还需要分配给方法区,栈内存,堆内存,那么堆内存大概就只有1G多内存空间

堆内存钟还有年轻代和老年代,老年代大概给几百MB内存空间,新生代也就只有几百MB空间

这几百MB都会内存空间,是不是几百秒后,新生代就满了,发生YoungGC了

如果频繁发生YoungGC会影响线上性能稳定性,因此可以选择4核8G的机器部署,这样分给新生代的内存有2G内存

这样就可以做的新生代每秒1MB左右内存,要半个小时到1个小时才会发生Young GC

每日百万交易的支付系统,JVM堆内存与永久代如何设置

不合理设置内存的反面例子

假设线上JVM的堆大小就只有1G,扣除老年代后,新生代就只有几百MB

但是我们都会支付系统1s就会创建1MB左右的对象

那我们发现稍微几分钟系统就会卡顿一下,因为这个时候在进行垃圾回收,其会影响系统性能

那么如果我们系统处于双11这样的大促销时期,压力瞬间扩大10倍,这时系统各个资源压力都特别大

年轻代的对象太大了,导致没有被及时回收,从而让一部分对象去老年代去

老年代对象越来越多,会频繁触发老年代对象回收,但是因为老年代垃圾回收速度很慢大大影响性能

如何设置永久代大小和栈内存大小?

一般来说刚上线的系统,永久代一般设置为几百MB

栈内存大小一般默认是512KB到1MB左右

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐