JVM学习日记⭐️实战:对象的内存分配⭐️

626 阅读3分钟

🔉引言

我们说java技术的内存管理无非就是解决两件事情:对象的内存分配和回收,关于回收我已经介绍了大量的篇幅,所以我们来聊聊前面没有提到的对象的内存分配。

对象的分配一般都是分配在堆中的,按照分代理论,新对象被分配在新生代,少数情况下,也可能直接分配在老年代,对象的分配规则并不是确定的,《java虚拟机规范》中也没有给出具体的规则,这取决于我们使用哪款垃圾收集器。

对象的分配

对象优先在Eden区分配,那Eden区要是没有空间呢?就会触发一次MinorGC。下面我将实战解析一下分配过程:

实战GC方式

那在讲解具体的分配过程之前,我们先偷瞄一下JDK的默认GC方式,通过java -XX:+PrintCommandLineFlags -version命令查询,如下图:

image.png

可以非常明显的看出,实验用的是UseParallelGC,我就不改了,大家要改的话可以改,比如我们要改Serial,那就-XX:+UseSerialGC 配置。

实战代码

然后我搞了一段代码,搞了32MB对象和14MB的对象,别问为什么,因为心情。

package jvm;

public class TestAlloCation {
    private static final int _1MB = 1024 * 1024;
    public static void main(String[] args) {
        byte[] bytes1 = new byte[_1MB * 2];
        byte[] bytes2 = new byte[_1MB * 2];
        byte[] bytes3 = new byte[_1MB * 2];
        byte[] bytes4 = new byte[_1MB * 4];
        System.out.println(bytes1);
        System.out.println(bytes2);
        System.out.println(bytes3);
        System.out.println(bytes4);

    }
}

参数设置

之后,我们来配置虚拟机参数,没有参数的虚拟机那能叫虚拟机嘛?

image.png

我们来分析一下这些参数,作用如下:

  1. 指定堆的大小是20M,而且是不可变的
  2. 打印GC详情,要不我们看啥呢?
  3. 指定新生代的Eden和Survivor区的比列:8比1

image.png

日志分析

eden space 8192K, 78% used from space 1024K, 88% used to pace 1024K,确实是81,新生代可用空间为9126k,分配失败了,分配第四个对象的时候发现空间不够4M,发生了一次MinorGC,使新生代由[PSYoungGen: 6804K->959K(9216K)],但总内存并没有减少,原因是前三个对象依然是存活对象,eden区位置不够,Survivor只有1M,也不够,故把Eden区的三个对象分配到老年代,图如下。

image.png

image.png

日志分析纠错

那按理说:老年代应该有6M啊,怎么才4M呢? image.png

我后来经过10分钟的思考,发现多了1M是我们定义的成员变量,我们来重新梳理一下:1M的成员和22M的对象分配进去,此时,Eden已经是6M多了,大概是6742k,那还剩2474k,由于还得预留一部分空间,已经不够玩的了,就发生第一次MinorGC,[PSYoungGen: 6578K->968K(9216K)],然后在把第三个对象分配进去,内存占有是3182K,把剩余的4M对象放到老年代,老年代内存占用就是4104K,再来一个对象,新生代就是7369K了,也就对应我们分析之前的场景。

图如下: image.png

📝题外话

当在一个现象综合体中起作用的因素太多时,绝大多数情况下,科学方法是不起作用的。人们只要想想天气就知道了,哪怕只是对几天之后的天气进行预报也不可能。然而没有人怀疑我们正面临一种因果联系,其中构成原因的成分大体上已为我们所知。人们不能对这个领域发生的事情进行精确的预测,是因为起作用的因素具有多样性,而不是因为自然界中缺乏秩序。