使用Java VisualVM观察过期对象引用现象

《Effective Java》书中第7条中提到:一般来说,只要类是自己管理内存,程序员就应该警惕内存泄漏问题。一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。

此次测试过程我用的jdk8,在jdk的bin目录下可以找到jvisualvm.exe,双击打开。

idea设置堆内存限制-Xmx100M -Xms100M ,如下图所示

测试代码如下:

java 复制代码
import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final  int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack(){
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e){
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop(){
        if(size == 0){
            throw new EmptyStackException();
        }
        Object element = elements[--size];
        return element;
    }

    private void ensureCapacity(){
        if(elements.length == size){
            elements = Arrays.copyOf(elements, 2 * size +1);
        }
    }
}
java 复制代码
public class ObsoleteReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        Stack stack = new Stack();
        // 压入大量大对象
        for (int i = 0; i < 80; i++) {
            stack.push(new byte[1024 * 1024]);
            System.out.println("压入第 " + i + " 个 1MB 数组");
        }
        // 全部弹出!业务上不再使用这些对象
        for (int i = 0; i < 80; i++) {
            stack.pop();
        }
        System.out.println("所有对象pop完成,业务层面不再使用");

        Thread.sleep(30000);
    }
}

运行代码后,进入Java VisualVM,在左侧找到当前代码运行的程序,双击,然后点击右侧上方的"监视",如下图所示

等待idea控制台输出 所有对象pop完成,业务层面不再使用 后点击"执行垃圾回收"按钮,如下图所示,可以看到,堆内存的使用量并没有明显下降。说明elements 数组内部仍然持有大量byte对象引用。

修改pop()方法,手动清空过期引用

typescript 复制代码
public Object pop(){
    if(size == 0){
        throw new EmptyStackException();
    }
    Object element = elements[--size];
    //手动清空过期引用
    elements[size] = null;
    return element;
}

再次运行代码,点击执行垃圾回收,观察堆使用情况,等待idea控制台输出 所有对象pop完成,业务层面不再使用 后点击"执行垃圾回收"按钮,可以看到堆使用量大幅下降,说明大量过期对象已被回收。

相关推荐
边境悍匪9 小时前
蜗牛学苑 Java 智能体学习 Day49|贯穿项目 5 订单下单业务 思维导图复盘
java·开发语言·spring boot·学习·阿里云
鬼手点金9 小时前
Claude Code示范案例-修复 Bug 工作流
java·服务器·前端·javascript·bug·openclaw
一条破秋裤9 小时前
Linux 进程通信介绍:内存隔离与 IPC 分类
java·linux·服务器
机核研创社10 小时前
polo 长袖短裤套装自动化产线:八台机器排队接力
android·java·自动化
Roadinforest10 小时前
Spring Boot 4 六步入门实录:从 Hello World 到一个能交付的 Todo API
java·开发语言·spring boot·spring
半仙白桑10 小时前
内核篇第十三讲:system-V消息队列
java·linux·网络
今天的砖头有点烫手啊10 小时前
GC 算法与垃圾收集器演进:从 Serial 到 ZGC
java·jvm
牧瀬クリスだ10 小时前
Mybatis-Plus:让CRUD快如闪电
java·spring boot·spring·tomcat·mybatis·yml
盐焗鹌鹑蛋10 小时前
【Linux】线程概念和控制
java·linux·服务器
CarIise10 小时前
MyBatis缓存与分页插件:从一级二级缓存到底层原理与PageHelper实战
java·开发语言·spring