研究一下Java的内存管理

 这里用一些简单的例子看一下JVM的内存使用与管理方式。

 

1.建立一简单程式,查看默认情况下JVM可使用的最大内存

public class MemoryDemo{
    public static void main(String[] args){
        System.out.println(Runtime.getRuntime().maxMemory());
    }
}
运行结果为66,650,112,也即约为64M

2.建立一个大的字符串数组,查看内存的使用情况

public class MemoryDemo{
    String[][] list = new String[100][100000];

    public static void main(String[] args){
        MemoryDemo demo = null;
        long memoryUsed = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        demo = new MemoryDemo();
        System.out.println(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() - memoryUsed);
    }
}
运行结果:39,921,008,根据Java API中的资料,这个数据的单位为byte,我们分配的数组的大小为:100 * 100000 = 10,000,000,也即数组中的每个Item占用的空间大概为4 bytes。

3.简单修改代码,可引起OutOfMemoryError

public class MemoryDemo{
    String[][] list = new String[100][100000];

    public static void main(String[] args){
        MemoryDemo demo = null;
        int i = 0;
        while(i++ < 10){
            System.out.println(i);            
            demo = new MemoryDemo();
        }
    }
}
可以看到,初始化第二个MemoryDemo对象时内存溢出。

4.修改代码,重写finalize方法,查看JVM内存回收情况

public class MemoryDemo{
    String[][] list = new String[100][100000];

    public static void main(String[] args){
        MemoryDemo demo = null;
        int i = 0;
        while(i++ < 10){
            System.out.println(i);            
            demo = new MemoryDemo();
        }
    }

    protected void finalize(){
        System.out.println("System run gc");
    }
}
运行代码,当然仍时错误,说明JVM没有运行gc释放内存

5.修改代码,在循环内将demo指向null,并调用gc,以使JVM将第一次新建对象标记为可回收

public class MemoryDemo{
    String[][] list = new String[100][100000];

    public static void main(String[] args){
        MemoryDemo demo = null;
        int i = 0;
        while(i++ < 10){
            System.out.println(i);            
            demo = new MemoryDemo();
            demo = null;
            System.gc();
        }
    }

    protected void finalize(){
        System.out.println("System run gc");
    }
}
再次运行,程式可正常运行,结果如下:1
2
System run gc
3
System run gc
4
System run gc
5
System run gc
6
System run gc
7
System run gc
8
System run gc
9
System run gc
因我们的最大内存为64M,而数组分配占用的内存为40M,所以如果不进行内存的回收,程式应该只能跑一次循环,这里JVM可以正常进行内存的回收。 

6.删除上例中的System.gc(),再次运行,

结果如下:1
2
System run gc
3
System run gc
4
System run gc
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at MemoryDemo.<init>(MemoryDemo.java:2)
        at MemoryDemo.main(MemoryDemo.java:9)程式会在循环的某处发生OutOfMemoryError,可以看到JVM本身的内存回收似乎还有一点问题。

7.增大JVM内存,使其最大内存略大于数组所需内存的2倍,

即运行时使用 java -Xmx75m MemoryDemo,发现循环仍然会有中断情况,继续加大内存到略大于所需内存的3倍,即java Xmx121m MemoryDemo,可正常运行,未再发现有OutOfMemoryError,不知JVM是否需要分配至少三倍于所需内存才可正常运行,有待确认。

8.回到第5例,去除代码中的demo = null

public class MemoryDemo{
    String[][] list = new String[100][100000];

    public static void main(String[] args){
        MemoryDemo demo = null;
        int i = 0;
        while(i++ < 10){
            System.out.println(i);            
            demo = new MemoryDemo();
            System.gc();
        }
    }

    protected void finalize(){
        System.out.println("System run gc");
    }
}
运行仍然会报OutOfMemoryError,增大内存至121m,代码可正常运行,分析原因为:由于没有使用demo = null语句及时将demo制空,致使下次循环重新赋值时才制空,因此内存回收会延后一次循环。
以上或有错误,请大家留言。
posted @ 2008-07-31 15:30  moonsnow  阅读(170)  评论(0编辑  收藏  举报