首页 > 系统相关 >如何避免Java内存泄漏,来看看这个

如何避免Java内存泄漏,来看看这个

时间:2023-10-10 23:05:19浏览次数:33  
标签:泄漏 Java void private 内存 new public

大家好,我是老七,关注我,将持续更新更多精彩内容!

如何避免Java内存泄漏,来看看这个_内部类

在日常的Java开发中,开发人员经常面临着一种令人难以捉摸且具有潜在破坏性的问题——内存泄漏。尽管Java拥有高效的垃圾收集器(GC),但仍然难以完全避免与内存相关的陷阱。

接下来,我们将通过实际示例来深入了解Java中内存泄漏的常见原因。

注意:请记住,所提供的技术旨在作为识别和定位内存泄漏的参考。它们可能并不直接适用于您的特定代码。

内部类引用

非静态内部类持有对其外部类的隐式引用。如果它们的寿命比外部类长,则可能会导致内存泄漏。

public class OutClass {
    private TestObject obj = new TestObject();

    public Runnable createRunnable() {
        return new InnerRunnable();
    }

    private class InnerRunnable implements Runnable {
        @Override
        public void run() {
            // ... 业务逻辑
        }
    }
}

解决方案:使用静态内部类或单独的类。静态内部类不保存对外部类实例的隐式引用。这种解耦确保内部类的生命周期不与外部类绑定,从而防止潜在的内存泄漏。

public class OuterClass {
    private TestObject obj = new TestObject();

    public Runnable createRunnable() {
        return new StaticInnerRunnable(obj);
    }

    private static class StaticInnerRunnable implements Runnable {
        private TestObject ref;

        public StaticInnerRunnable(TestObject ref) {
            this.ref = ref;
        }

        @Override
        public void run() {
            // ... 业务逻辑
        }
    }
}

没有封闭资源

没有关闭流、没有断开连接或关闭文件等资源都可能会导致内存泄漏。

public void readFile(String fileName) throws IOException {
    FileInputStream fis = new FileInputStream(fileName);
    // 读取文件
    // 缺少 fis.close(); 
}

解决方案:始终关闭finally块中的资源或使用 try-with-resources 语句。

public void readFileSafely(String fileName) throws IOException {
    try (FileInputStream fis = new FileInputStream(fileName)) {
        // 读取文件
    } // fis 自动关闭
}

静态集合

无限增长的静态集合可能会导致内存泄漏,因为它们的生命周期与应用程序的生命周期相关。

public class MemoryLeakExample {
    private static final List<Object> leakyList = new ArrayList<>();
    
    public void addToLeakyList(Object obj) {
        leakyList.add(obj);
    }
}

解决方案:限制集合的大小或定期清除它。

public class FixedMemoryLeakExample {
    private static final List<Object> safeList = new ArrayList<>();
    
    public void addToSafeList(Object obj) {
        if (safeList.size() > 1000) {
            safeList.clear();
        }
        safeList.add(obj);
    }
}

线程局部变量

如果线程不终止,ThreadLocal 变量可能会导致内存泄漏,特别是在线程池场景中。

public class ThreadLocalLeak {
    private static ThreadLocal<TestObject> threadLocal = ThreadLocal.withInitial(() -> new TestObject());

    public void useThreadLocal() {
        TestObject obj = threadLocal.get();
        // ... 业务逻辑
    }
}

解决方案:当不再需要 ThreadLocal 变量时,始终将其删除。

public void safeUseThreadLocal() {
    try {
        TestObject obj = threadLocal.get();
        // ... 业务逻辑
    } finally {
        threadLocal.remove();
    }
}

监听器和回调

注册侦听器而不取消注册它们可能会导致内存泄漏。

public class EventProducer {
    private List<EventListener> listeners = new ArrayList<>();

    public void registerListener(EventListener listener) {
        listeners.add(listener);
    }
}

解决方案:始终提供注销侦听器的机制。

public void unregisterListener(EventListener listener) {
    listeners. Remove(listener);
}

缓存对象

存储在缓存中的对象在内存中的保留时间通常会超过必要的时间。

public class Cache {
    private Map<String, Object> cache = new HashMap<>();

    public void put(String key, Object value) {
        cache.put(key, value);
    }
}

解决方案:使用支持过期的缓存库,例如EhCache或Guava的Cache。

public class SafeCache {
    private Cache<String, Object> cache = CacheBuilder.newBuilder()
        .expireAfterAccess(5, TimeUnit.MINUTES)
        .build();

    public void put(String key, Object value) {
        cache.put(key, value);
    }
}

持有大对象的单例类

持有大对象的单例类可能会导致内存泄漏。

public class Singleton {
    private static Singleton instance;
    private TestObject obj = new TestObject();

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

解决方案:确保单例持有对象的时间不会超过必要的时间。

public void releaseResources() {
    obj = null;
}

数据库连接

不关闭数据库连接可能会导致内存泄漏。

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test", "user", "password");
// ... 使用连接
// 缺少 conn.close();

解决方案:使用后始终关闭数据库连接。

try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test", "user", "password")) {
    // ... 使用连接
} // conn自动关闭

加载和卸载类

连续的类加载和卸载,特别是在使用自定义类加载器的情况下,可能会引发内存泄漏的风险,尤其是在频繁加载和卸载类时。

因此,我们必须谨慎地处理类加载器和加载的类的生命周期。确保类加载器可以被垃圾回收,并不会对已加载的类产生延迟引用。

通过了解内存泄漏的常见原因并实施提供的解决方案,您可以确保Java应用程序保持高效和响应迅速。

请记住,防止内存泄漏是解决问题的最佳方法。

标签:泄漏,Java,void,private,内存,new,public
From: https://blog.51cto.com/u_16277888/7800268

相关文章

  • 如何用IDEA生成Javadoc
    在IDEA的工具选项卡中选择生成JavaDoc如图所示生成JavaDoc​ -encodingUTF-8-charsetUTF-8......
  • java RestTemplate 发送post请求
    case1:POST,格式:application/json/***采用POST请求,数据格式为application/json,并且返回结果是JSONstring*@paramurl*@param*@return*/publicstaticStringpostForJson(Stringurl,JSONObjectjson){RestTemplaterestTemplate=newRestTemplate(......
  • 《剑指offer》面试题的Java实现-从尾到头打印链表
    输⼊⼀个链表的头节点,按链表从尾到头的顺序返回每个节点的值(⽤数组返回)。⽐如下⾯的链表: publicstaticclassLinkNode{intvalue;LinkNodenext;LinkNode(intvalue){this.value=value;}}//思路:将链表进行遍历,在遍历的过程中记录元素的个数,//然......
  • 运算符-包机制-javaDoc生成文档
    publicclassDemo12{publicstaticvoidmain(String[]args){//与(and)或(or)非(取反)booleana=true;booleanb=false;System.out.println("a&&b:"+(b&&a));//逻辑与运算:两个变量都为真,结果才为trueSystem.......
  • 如何在JavaScript中验证电子邮件地址?
    内容来自DOChttps://q.houxu6.top/?s=如何在JavaScript中验证电子邮件地址?我想在将用户输入发送到服务器或尝试向其发送电子邮件之前,在JavaScript中检查它是否是电子邮件地址,以防止最基本的拼写错误。我该如何实现?使用正则表达式可能是在JavaScript中验证电子邮件地址的最......
  • 在JavaScript中,如何替换所有出现的字符串?
    内容来自DOChttps://q.houxu6.top/?s=在JavaScript中,如何替换所有出现的字符串?给定一个字符串:s="Testabctesttestabctesttesttestabctesttestabc";这似乎只删除了上面字符串中的第一个abc:s=s.replace('abc','');如何替换所有的它的出现?在大多数流......
  • 【Android面试】2023最新面试专题六:Java并发编程(一)
    1、假如只有一个cpu,单核,多线程还有用吗?详细讲解享学课堂移动互联网系统课程:架构师筑基必备技能《线程与进程的理论知识入门1》这道题想考察什么?是否了解并发相关的理论知识考察的知识点cpu多线程的基本概念操作系统的调度任务机制CPU密集型和IO密集型理论考生应该如何回答CPU的执......
  • Powershell 获取磁盘及内存信息
    functionGet-Resources{param($computername=$env:computername)$Info=""|SelectComputerName,Memery,DiskSize,FreeDSize$info.ComputerName=$computername#Processorutilization#$cpu=gwmiwin32_per......
  • Java观察者模式-SpringBoot实现观察者模式
    观察者模式一、Java观察者模式Java观察者模式是一种设计模式,用于实现对象之间的一对多依赖关系。在观察者模式中,当一个对象的状态发生变化时,它的所有依赖对象(观察者)都会自动收到通知并进行相应的更新。观察者模式由以下几个核心组件组成:主题(Subject):也称为被观察者或可观察对......
  • Java 集合
    目录Java集合List,Set,Queue,Map的区别集合框架底层数据结构CollectionListSetQueueMap如何选用集合?ListArrayList和Array(数组)的区别转换ArrayList转换为数组数组转换为ArrayListSetComparable和Comparator的区别Comparable接口Comparator接口总结HashSetLinkedHas......