GC过后,存活对象在移动后,内存地址会改变么?

先新建一个工具类AddressPrint,用来打印对象内存地址,如下:

package com.example.springboot.codedemo;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class AddressPrint {
     
    private static Unsafe unsafe;

    static {
     
        try {
     
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
        } catch (Exception e) {
     
            e.printStackTrace();
        }
    }

    public static String addressOf(Object o)
            throws Exception {
     
        Object[] array = new Object[]{
     o};

        long baseOffset = unsafe.arrayBaseOffset(Object[].class);
        int addressSize = unsafe.addressSize();
        long objectAddress;
        switch (addressSize) {
     
            case 4:
                objectAddress = unsafe.getInt(array, baseOffset);
                break;
            case 8:
                objectAddress = unsafe.getLong(array, baseOffset);
                break;
            default:
                throw new Error("unsupported address size: " + addressSize);
        }

        return (Long.toHexString(objectAddress));
    }


    public static void printBytes(long objectAddress, int num) {
     
        for (long i = 0; i < num; i++) {
     
            int cur = unsafe.getByte(objectAddress + i);
            System.out.print((char) cur);
        }
        System.out.println();
    }
}

先修改JVM运行参数如下:

-Xmx10m :最大堆大小
-Xms10m :初始堆大小
-XX:+PrintGC:打印GC详细日志

测试demo

package com.example.springboot.codedemo;

public class TestMain {
     
    private static byte[] bytes = new byte[5 * 1024 * 1024];

    public static void main(String[] args) throws Exception {
     
        System.out.println("分配在新生代的内存地址:" + AddressPrint.addressOf(bytes));
        for (int i = 0; i < 20; i++) {
     
            byte[] bytes1 = new byte[1024 * 1024];
        }
        System.out.println("分配在老年代的内存地址:" + AddressPrint.addressOf(bytes));
    }
}

运行结果如下:GC过后,存活对象在移动后,内存地址会改变么?_第1张图片
由于bytes变量是static修饰符修饰的,属于类变量,而byte[]对象的大小是5M左右,系统分配给JVM的堆大小只有10M,正常情况此时新生代大致占据3M左右,那Survivor区就更小了,是放不下byte[]对象的,所以一次新生代GC过后,该对象会直接进入老年代,而从输出结果可以看出byte[]对象在新生代和在老年代中的内存地址是不同的,所以可以得出结论,GC过后,存活对象在移动后,内存地址会改变。

你可能感兴趣的:(JVM)