这里用一些简单的例子看一下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.
(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制空,致使下次循环重新赋值时才制空,因此内存回收会延后一次循环。
以上或有错误,请大家留言。