excel百萬數據處理,內存溢出問題,Java常見溢出問題解決

小G最近搞一個導出excel項目,但是數據量比較多導出來tomcat內存狂飆,開始使用xssf內存狂升,後來使用sax還好點,但是
行數到5萬左右,就2G,
第一步驟定位:liunx上面使用jmap -histo |head -30
在這裏插入圖片描述
可以查到使用內存最多是C和1,2,c是char[] ,1,2爲xml的解析,那就可以看到時poi在解析過程中使用
第二步,找到問題後對問題進行分析
分析結果如下:
自測過程中數據問題:

解析方法 excel行數 內存情況
SXSSFWorkbook 5萬行 2-4G內存
XSSFWorkbook 幾千行 G級別反正內存消耗很大

第三步解決思路:
1、新增多個sheetname效果雖然好點,但是內存還是不怎麼樣在執行到10萬左右,該方不可行;
2、分多個文件,5萬-6萬到2G,應該可以;
3、調用gc進行垃圾回收;
4、加鎖共享鎖lock,因爲執行多個的話,就會2G的倍數,所以加一個鎖,針對服務器加鎖,其實在讀取的時候內存比較大,但是這個是瞬間的,(如果數據不超過1萬條,是可以沒有問題,不用加鎖),這樣就可以同時執行多個文件進行導出操作
5,讀取的時候使用sax進行讀取數據

	public static Lock lockPOItool = new ReentrantLock();// 鎖對象
    public static  void poi(){ 
     Boolean isLockBoolean =false;
     if(lockPOItool.tryLock(5l, TimeUnit.MINUTES){
     isLockBoolean=true;
     //獲取鎖成功
     }
			XSSFWorkbook xssfworkbook = null;
			SXSSFWorkbook workbook = null;
			SXSSFSheet sheet = null;
			sheetName =  null ;
			fileName = null;
			sheetName="根據業務去劃分生成多excel";
			fileName=sheelNameCount.toString()+fileName;
			FileInputStream fileInputStream =new FileInputStream(path);//原來的地址
			SXSSFCell cell=null;
			XSSFSheet xssheet=null;
			POIFSFileSystem pfs =null;
                  try{
                  //如果有文件說明以前新建過直接進行追加
                  Boolean  isFrist = new File(path+ fileName).exists();
                   if(i!sFrist){
                 workbook = new SXSSFWorkbook();
				sheet = workbook.createSheet(sheetName);
				SXSSFRow row = sheet.createRow((short) 0);
			    cell = row.createCell((short) 0);
				//如果有標題創建標題
				rowNum = sheet.getLastRowNum() + 1;//有標題+1從第二行進行
             }else{
             //追加操作的
                     pfs = new POIFSFileSystem(fileInputStream);
					EncryptionInfo encInfo = new EncryptionInfo(pfs);
					Decryptor decryptor = Decryptor.getInstance(encInfo);
					decryptor.verifyPassword(pwd);//讀取加密的這個是追加的方法 xssf解密,然後讀取到sxssf裏面
					InputStream pfsInputStream=decryptor.getDataStream(pfs);
					xssfworkbook = new XSSFWorkbook(pfsInputStream);
					pfsInputStream.close();
					pfs.close();
					xssheet = xssfworkbook.getSheet(sheetName);
					rowNum = xssheet.getLastRowNum() + 1;
					workbook = new SXSSFWorkbook(xssfworkbook,-1);//-1就是不在使用內存
				    sheet=workbook.getSheet(sheetName);
		  }
         //
           while(rowNum<50){
              //數據的存放
               SXSSFRow row = sheet.createRow(rowNum);
				row.createCell(0).setCellValue(“”“”);//
				row.createCell(1).setCellValue(“”“”);//
				//官網說這個在(xssfworkbook,-1);有內存中使用,反正這個地方使用也可以
				((SXSSFSheet)sheet).flushRows(dataModels.size()-dataModelsInde);
	                 rowNum++;
	             }
	           FileOutputStream outBuildE=null;
	         try{
		   	outBuildE = new FileOutputStream(path + filename);
			outBuildE.flush();
			workbook.write(outBuildE);
			outBuildE.close();
				workbook.dispose();
			}catch(Exception  e){
			
			}
				    xssfworkbook.close();
			        workbook.dispose();	
     }catch(Exception e){
         }finally{
                 workbook=null;
		    	xssfworkbook=null;
		    	sheet=null;
			    cell=null;
				xssheet=null;
				pfs=null;
				gcPoi();//緩存
				if(isLockBoolean){
				lockPOItool.unlock();
				}catch(Exception e){
				}
				
				
        }
   //手動清空下緩存  
  private void gcPoi(String msg) {
	try {
		Runtime.getRuntime().gc();
		}catch(Exception e){
		}
	}

官方的接口如下3.8大家可以看下

public static void main(String[] args) throws Throwable {
  SXSSFWorkbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
    Sheet sh = wb.createSheet();
    for(int rownum = 0; rownum < 1000; rownum++){
        Row row = sh.createRow(rownum);
        for(int cellnum = 0; cellnum < 10; cellnum++){
            Cell cell = row.createCell(cellnum);
            String address = new CellReference(cell).formatAsString();
            cell.setCellValue(address);
        }

    }

    // Rows with rownum < 900 are flushed and not accessible
    for(int rownum = 0; rownum < 900; rownum++){
      Assert.assertNull(sh.getRow(rownum));
    }

    // ther last 100 rows are still in memory
    for(int rownum = 900; rownum < 1000; rownum++){
        Assert.assertNotNull(sh.getRow(rownum));
    }
    
    FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
    wb.write(out);
    out.close();

    // dispose of temporary files backing this workbook on disk
    wb.dispose();
}
}

官方如下:

    public static void main(String[] args) throws Throwable {
        SXSSFWorkbook wb = new SXSSFWorkbook(-1); // turn off auto-flushing and accumulate all rows in memory
        Sheet sh = wb.createSheet();
        for(int rownum = 0; rownum < 1000; rownum++){
            Row row = sh.createRow(rownum);
            for(int cellnum = 0; cellnum < 10; cellnum++){
                Cell cell = row.createCell(cellnum);
                String address = new CellReference(cell).formatAsString();
                cell.setCellValue(address);
            }

           // manually control how rows are flushed to disk 
           if(rownum % 100 == 0) {
                ((SXSSFSheet)sh).flushRows(100); // retain 100 last rows and flush all others

                // ((SXSSFSheet)sh).flushRows() is a shortcut for ((SXSSFSheet)sh).flushRows(0),
                // this method flushes all rows
           }

        }

        FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
        wb.write(out);
        out.close();

        // dispose of temporary files backing this workbook on disk
        wb.dispose();
   }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章