在Java中导致内存泄漏的最简单方法

在Java中导致内存泄漏的最简单方法,java,memory-leaks,Java,Memory Leaks,可能重复: 导致Java内存泄漏的最简单方法是什么 在类范围内创建对象集合 定期向集合中添加新对象 不要删除对保存集合的类实例的引用 由于始终存在对集合和拥有该集合的对象的实例的引用,垃圾收集器将永远不会清理该内存,从而随着时间的推移导致“泄漏”。使用: public static List<byte[]> list = new ArrayList<byte[]>(); publicstaticlist=newarraylist(); 然后添加(大)阵列而不删除它们

可能重复:

导致Java内存泄漏的最简单方法是什么

  • 在类范围内创建对象集合
  • 定期向集合中添加新对象
  • 不要删除对保存集合的类实例的引用
  • 由于始终存在对集合和拥有该集合的对象的实例的引用,垃圾收集器将永远不会清理该内存,从而随着时间的推移导致“泄漏”。

    使用:

    public static List<byte[]> list = new ArrayList<byte[]>();
    
    publicstaticlist=newarraylist();
    
    然后添加(大)阵列而不删除它们。在某个时刻,你会毫无疑问地耗尽内存。(您可以对任何对象执行此操作,但对于大而完整的阵列,您可以更快地耗尽内存。)


    在Java中,如果取消引用一个对象(它不在范围内),它将被垃圾收集。因此,您必须保留对它的引用才能出现内存问题。

    下面是一个简单的示例

    public class Finalizer {
        @Override
        protected void finalize() throws Throwable {
            while (true) {
                Thread.yield();
            }
        }
    
        public static void main(String[] args) {
            while (true) {
                for (int i = 0; i < 100000; i++) {
                    Finalizer f = new Finalizer();
                }
    
                System.out.println("" + Runtime.getRuntime().freeMemory() + " bytes free!");
            }
        }
    }
    
    公共类终结器{
    @凌驾
    受保护的void finalize()抛出可丢弃的{
    while(true){
    螺纹屈服强度();
    }
    }
    公共静态void main(字符串[]args){
    while(true){
    对于(int i=0;i<100000;i++){
    终结器f=新终结器();
    }
    System.out.println(“+Runtime.getRuntime().freemory()+”bytes free!”);
    }
    }
    }
    
    从我在投票最多的答案中读到的内容来看,您很可能是在要求类似C的内存泄漏。因为存在垃圾收集,所以不能分配一个对象,丢失它的所有引用,让它仍然占用内存——这将是一个严重的JVM错误

    另一方面,您可能会发生线程泄漏-当然,这会导致这种状态,因为您可能会有一些线程在运行时引用了对象,并且可能会丢失线程的引用。您仍然可以通过API获取线程引用-请参见尝试以下简单类:

    public class Memory {
        private Map<String, List<Object>> dontGarbageMe = new HashMap<String, List<Object>>();
    
        public Memory() {
            dontGarbageMe.put("map", new ArrayList<Object>());
        }
    
        public void useMemInMB(long size) {
            System.out.println("Before=" + getFreeMemInMB() + " MB");
    
            long before = getFreeMemInMB();
            while ((before  - getFreeMemInMB()) < size) {
                dontGarbageMe.get("map").add("aaaaaaaaaaaaaaaaaaaaaa");
            }
    
            dontGarbageMe.put("map", null);
    
            System.out.println("After=" + getFreeMemInMB() + " MB");
        }
    
        private long getFreeMemInMB() {
            return Runtime.getRuntime().freeMemory() / (1024 * 1024);
        }
    
        public static void main(String[] args) {
            Memory m = new Memory();
            m.useMemInMB(15);  // put here apropriate huge value
        }
    }
    
    公共类内存{
    私有映射dontGarbageMe=newhashmap();
    公共内存(){
    put(“map”,新的ArrayList());
    }
    公共空间useMemInMB(长尺寸){
    System.out.println(“Before=“+getFreeMemInMB()+”MB”);
    很久以前=getFreeMemInMB();
    而((在-getFreeMemInMB()之前)
    “在计算机科学中,当计算机程序消耗内存但无法将其释放回操作系统时,就会发生内存泄漏(或在此上下文中的泄漏)。”(维基百科)

    简单的答案是:你不能。Java会自动管理内存,并释放您不需要的资源。你无法阻止这一切的发生。它将始终能够释放资源。在使用手动内存管理的程序中,这是不同的。您可以使用malloc()在C中获得一些内存。要释放内存,需要malloc返回的指针并对其调用free()。但是如果您不再拥有指针(被覆盖,或者超过了生命周期),那么很遗憾,您无法释放此内存,因此内存泄漏


    到目前为止,所有其他的答案在我的定义中都不是真正的内存泄漏。他们的目标都是用毫无意义的东西快速填满记忆。但在任何时候,您仍然可以取消对所创建对象的引用,从而释放内存→ 没有线索。不过,正如我不得不承认的那样,这非常接近,因为他的解决方案是通过无休止的循环强制垃圾收集器“崩溃”垃圾收集器)

    答案很长:您可以通过使用JNI编写Java库来获得内存泄漏,JNI可以进行手动内存管理,从而导致内存泄漏。如果调用此库,Java进程将泄漏内存。或者,JVM中可能存在bug,因此JVM会丢失内存。JVM中可能存在bug,甚至可能存在一些已知的bug,因为垃圾收集并不是那么简单,但它仍然是一个bug。按照设计,这是不可能的。您可能需要一些受此类bug影响的Java代码。很抱歉,我不知道其中一个,在下一个Java版本中,它可能不再是一个bug。

    除非您:

    • 实习串
    • 生成类
    • 调用的本机代码中存在内存泄漏
    • 把你不想要的东西放在遗忘或模糊的地方
    我认为你对最后一个案子感兴趣。常见的情况有:

    • 侦听器,尤其是内部类
    • 储藏室
    一个很好的例子是:

    • 构建一个Swing GUI,它可以启动无限数量的模式窗口
    • 让模态窗口在初始化期间执行以下操作:
      
      StaticGuiHelper.getMainApplicationFrame().GetOneOfButtons().addActionListener(新ActionListener()){
      已执行的公共无效操作(操作事件e){
      //什么也不做。。。
      }
      })
      
    注册的操作不起任何作用,但它会导致模式窗口永远在内存中徘徊,即使在关闭之后,也会导致泄漏-因为侦听器从未取消注册,并且每个匿名内部类对象都持有对其外部对象的引用(不可见)。此外,从模式窗口引用的任何对象也有泄漏的可能

    这就是像EventBus这样的库在默认情况下使用弱引用的原因

    除了听众之外,, StaticGuiHelper.getMainApplicationFrame().getOneOfTheButtons().addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ // do nothing... } })
    public class Scratch {
        public static void main(String[] args) throws Exception {
            long lastOut = System.currentTimeMillis();
            File file = new File("deleteme.txt");
    
            ObjectOutputStream out;
            try {
                out = new ObjectOutputStream(
                        new FileOutputStream("deleteme.txt"));
    
                while (true) {
                    out.writeUnshared(new LittleObject());
                    if ((System.currentTimeMillis() - lastOut) > 2000) {
                        lastOut = System.currentTimeMillis();
                        System.out.println("Size " + file.length());
                        // out.reset();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    class LittleObject implements Serializable {
        int x = 0;
    }
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Stack;
    
    public class Box <E> {
        private final Collection<Box<?>> createdBoxes = new ArrayList<Box<?>>();
        private final Stack<E> stack = new Stack<E>();
    
        public Box () {
            createdBoxes.add(this);
        }
    
        public void put (E e) {
            stack.push(e);
        }
    
        public E get () {
            if (stack.isEmpty()) {
                return null;
            }
            return stack.peek();
        }
    }