使用Memory Analyzer tool 检测OutofMemory异常
1.插件Memory Analyzer tool 的详细安装参考如下网址:
http://blog.csdn.net/yhc13429826359/article/details/7711911
2.我这次发生错误的程序代码如下:
public static void readLogBufferRead(String logPath){
BufferedReader bufferReader = null;
try{
bufferReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(logPath))));
String readLine = null;
int count = 0 ;
while((readLine = bufferReader.readLine()) != null){
System.out.println("count1:"+count+++"---"+readLine);
System.gc() ;
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(bufferReader != null){
try {
bufferReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3.检查程序发生错误原因的步骤:
1>根据异常原因确定是while((readLine = bufferReader.readLine()) != null)这行代码发生了堆溢出。
2>本次通过bufferReader读取的文件大小为2.66G,观察产生溢出的方法是否有对对象的强引用,发生没有对对象的强引用,只有一个String类型的readLine局部变量,但是每次读取的时候都会进行释放,否则jvm发现空间不够的时候也会进行空间的释放。
3>确定了不是局部变量的原因后确定是readLine()方法里面的内容发生了异常,就是jdk发生了内存溢出,观看BufferReader的源码,找到如下的代码:
public AbstractStringBuilder append(char str[], int offset, int len) {
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount);
System.arraycopy(str, offset, value, count, len);
count = newCount;
return this;
}
这是缓冲类在空间不够时申请分配空间的代码,另外读取的时候以文件的"\n"作为读取一行的标志,此时确定产生问题的原因有两个:一是java的堆空间设置不够大,二是读取的那一行已经超过了java堆的最大大小。
3>在程序运行时加入虚拟机的启动参数:-XX:+HeapDumpOnOutOfMemoryError ,这样就能够在抛出内存溢出错误时对产生的原因进行分析,产生的异常转储快照已经放在了附件中,经过Memory Analyzer tool 查看分析得出,系统要分配的内存过大,并没有对象不释放的情况,由此推断是读取的一行过于庞大,联想起文件写入的代码段如下:
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,true)));
writer.write(System.currentTimeMillis()+"|taiyuan|china|today|goodBoy|believe");
推断出来时换行符引起的。
4>证明猜想,利用程序生成同样大小的文件,每一行写入后都加入"\n",然后用同样的程序来读取文件,发生一切正常,事实证明是“\n"引起的。