Test.java:
import java.util.*;
import org.omg.SendingContext.RunTime;
public class Test {
int a;
int b;
int finalizeTimes = 0;
public Test(int a, int b) {
this.setA(a);
this.setB(b);
}
/**当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,
* 若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。
* 因为这个异常根据系统运行环境决定,所以无法预期它何时出现。
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Runtime rt = Runtime.getRuntime();
//rt.availableProcessors();
int num = 5 * 1024 * 1024;
Test[] ts = new Test[num];
List<Test> list = new ArrayList();
long freeMemory = 0;
long lastFreeMemory = 0;
/* for (int i = 0;i<num ;i++){
ts[i]= new Test(1,2);
freeMemory = rt.freeMemory();
if(freeMemory != lastFreeMemory){
System.out.println("maxMemory="+rt.maxMemory() / 1024 / 1024+"M");
System.out.println("totalMemory="+rt.totalMemory() / 1024 / 1024+"M");
System.out.println(rt.freeMemory()/1024+"K");
lastFreeMemory = freeMemory;
}
//Thread.sleep(100);
}
*/
/*
for (int i = 0;i<num ;i++){
Test t = new Test(1,2);
list.add(t);
freeMemory = rt.freeMemory();
if(freeMemory != lastFreeMemory){
System.out.println("maxMemory="+rt.maxMemory() / 1024 / 1024+"M");
System.out.println("totalMemory="+rt.totalMemory() / 1024 / 1024+"M");
System.out.println(rt.freeMemory()/1024+"K");
lastFreeMemory = freeMemory;
}
}
*/
for (int i = 0; i < num; i++) {
int a = i;
freeMemory = rt.freeMemory();
if (freeMemory != lastFreeMemory) {
System.out.println("maxMemory=" + rt.maxMemory() / 1024 / 1024+"M");
System.out.println("totalMemory=" + rt.totalMemory() / 1024/ 1024+"M");
//只要totalMeory < maxMemory ,freeMemory会稳定在一个值,
System.out.println(rt.freeMemory()/1024+"K");
lastFreeMemory = freeMemory;
}
Thread.sleep(100);
}
/*
Test t1 = new Test(1,2);
Test t2 = new Test(1,2);
System.out.println(t1.equals(t2));
System.out.println(t1.equals(new Test(1, 2)));
System.out.println(t1 == t2);
*/
}
protected void finalize() {
this.finalizeTimes++;
try {
System.out.println("come in finalize,times = "+this.finalizeTimes);//这里的每个对象finalize后就被清楚,times始终为1
super.finalize();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
********************************************
1 finalize():
gc 只能清除在堆上分配的内存(纯java语言的所有对象都在堆上使用new分配内存),而不能清除栈上分配的内存(当使用JNI技术时,可能会在栈上分配内存,例如java调用c程序,而该c程序使用malloc分配内存时).因此,如果某些对象被分配了栈上的内存区域,那gc就管不着了,对这样的对象进行内存回收就要靠finalize().
举个例子来说,当java 调用非java方法时(这种方法可能是c或是c++的),在非java代码内部也许调用了c的malloc()函数来分配内存,而且除非调用那个了 free() 否则不会释放内存(因为free()是c的函数),这个时候要进行释放内存的工作,gc是不起作用的,因而需要在finalize()内部的一个固有方法调用它(free()).
finalize的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存.所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作.
2 finalize()在什么时候被调用?
有三种情况
1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候.
2.程序退出时为每个对象调用一次finalize方法。
3.显式的调用finalize方法
除此以外,正常情况下,当某个对象被系统收集为无用信息的时候,finalize()将被自动调用,但是jvm不保证finalize()一定被调用,也就是说,finalize()的调用是不确定的,这也就是为什么sun不提倡使用finalize()的原因.
3、内存溢出类型
1、java.lang.OutOfMemoryError: PermGen space
JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。
2、java.lang.OutOfMemoryError: Java heap space
第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。
注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。
4 性能检查工具使用
定位内存泄漏:
JProfiler工具主要用于检查和跟踪系统(限于Java开发的)的性能。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。
1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;
2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;
3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full GC的时候是不响应客户的交易请求的,非常影响系统性能。