月度归档:2014年10月

JVM探索之——内存管理(一)

本系列的第一篇文章,预计本系列最后面会有两三个案例。

      Java与C、C++不一样Java不需要Coder进行手动内存管理,而这一切都交给JVM进行自动内存管理,这从某种程度上来说也减轻了我们Coder不少的编码量,而我们是否还有必要了解JVM的内存管理机制呢,答案是否定的;因为Java也会和C、C++一样发生内存泄漏、内存溢出,尽管它发生这些事故会少很多,但一旦发生了而你又不了解他的内存管理机制这将是非常棘手的问题;还有个原因就是Java是运行在JVM上的,而不能JVM参数可能会影响到程序的执行性能,我们要想JVM在具体的应用中达到最优的性能那就必须了解JVM的内部机制;废话不多说现在开始JVM探索系列之——内存管理。

      根据《Java虚拟机规范》所规定的,Java虚拟机执行Java程序时它他管理的内存划分为几个区域,也就是运行时数据区(Run-Time Data Areas);这些区域的功能、生命周期各不相同,主要分为两大类:一种是随着JVM进程的启动而创建,随JVM进程消亡而销毁;一种是随着线程的创建而创建,随着线程的销毁而销毁,《Java虚拟机规范》规定的内存区域有如下图:

jvm1

红色边框的两块区域为所有线程共享的(JVM进程的启动而创建、进程消亡而销毁)
其他三块区域为线程隔离的(线程的创建而创建,随着线程的销毁而销毁)

如图所示,运行时数据区(Run-time Areas)分为:方法区(Method Areas)、堆(Heap)、Java栈(Java Stacks)、本地方法栈(Native method stacks)、PC寄存器(Register)组成;

1、PC寄存器(PC Register)
      PC寄存器(PC Register),用户存储当前运行的指令(字节码指令)地址,线程所私有的每个线程都有个独立的寄存器;如正在执行的是Java方法则存字节码指令地址,如是Native方法则值为空(undefined)。

2、Java虚拟机栈(Java Virtual Machine Stacks)
      Java虚拟机栈,线程独有生命周期与线程一致;Java虚拟机栈用于存放栈帧,Java方法执行时会创建一个栈帧(Stack Frame)存储局部变量表、操作数栈、动态链接、方法出口等信息,方法开始执行栈帧(Stack Frame)入Java虚拟机栈中,方法执行完成则出栈。(《Java虚拟机规范》规定Java虚拟机栈会抛出两种异常:StackOverlowError与OutOfMemoryError,第一种为栈线程请求栈容量超过Java虚拟机允许的最大容量,第二种为无法分配到足够的内存)。

3、堆(Heap)
      在java虚拟机中堆是所有线程锁共享的,Java虚拟机启动的时候创建,用于存放对象实例与数组内存分配,

4、本地方法栈(Native Method stack)
      用于执行Native方法,有些虚拟机把他与Java虚拟机栈合在一起,(如:HotSpot),抛出两种异常:StackOverlowError与OutOfMemoryError。

5、方法区(Method Areas)
      方法区与Java堆一样虚拟机启动的时候创建,所有线程共享;存储被虚拟机加载的类信息、运行时常量池、字段、方法数据即时编译器编译后的字节码内容等,存储的内容基本上来自class文件;不同的虚拟机实现方法区不一样,在HotSpot虚拟机中可以把方法区称为永生代,GC分代收集会对方法区进行回收。当方法区无法满足内存分配时,Java虚拟机将抛出一个OutOfMemoryError异常。

5.1  运行时常量池(Runtime Constant Pool)
      运行时常量池,方法区的一部分,类或接口常量池的运行时表现形式,存储编译后生成的字面量与符号引用(方法、字段的引用);可以在运行期间加入常量,String类的intern(),方法就是如此。无法申请到内存是抛出OutOfMemoryError异常。

介绍完JVM内存的各个区域后,我们来看一下下面的代码:

public class Model {
    private static int i=1;
    public Model() {
    }
}

    当我们实例化Model model=new Model()后,i将存储到方法区(Method Aeras)的运行时常量池(Runtime Constant Pool)中,实例化后的model的引用(reference)将存储到Java虚拟机栈本地变量表中,而new Model()对应的实例(实例数据)将存储到Java堆(Java Heap)中,构造函数Model()也将存储到方法区中。

Apache POI笔记—生成excel导出

都说好记性不如烂笔头,poi也用过几次,不过这两天用到的时候还是要找资料,索性趁中午休息的时间做个记录。

Demo功能:导出excel

Demo流程:
1、点击web页面的导出按钮,Servlet后台根据web页面的条件查数据传导出Excel的ExcelGenerate类;
2、ExcelGenerate用poi读取excel模版文件,把数据后填充进poi读取的excel中,设置好单元格样式等;
3、然后把poi读取的excel写入输出流(OutStream),把输出流转换为输入流(InputStream)返回给Servlet;
4、Servlet设置好Response的ContentType与Header的信息为application/ms-excel、与”Content-disposition”,”attachment;filename=””+filename+”””,把输入流写入到Response的输出流(OutStream)中,关闭输入流(InputStream)、输出流(OutStream)。

Servlet类:

public class OriginalDataServlet extends HttpServlet {

protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
List<OriginalDataRes> originalDataRes = originalRes.getOriginalDataList();

String path;
String filename=”test.xls”;
//设置文件ContentType类型
response.setContentType(“application/ms-excel”);
response.setHeader(“Contentdisposition”,”attachment;filename=””+filename+”””);

path=request.getSession().getServletContext().getRealPath(“/resource/”);
ExcelGenerate generate = new ExcelGenerate(path,originalDataRes);

//取得生成excel后的输入流
InputStream input = generate.GenerateFileStream();
OutputStream output = response.getOutputStream();     //response输出流
int b = 0;
byte[] buffer = new byte[512];
while ((b=input.read(buffer))!= -1) {          //excel输入流写到response输出流中
output.write(buffer, 0, b);
}

} catch (Exception e) {
e.printStackTrace();
}finally{
input.close();
output.close();
}

}

}

ExcelGenerate类:

public class ExcelGenerate {

private List<Model> modelList;
private String path;

public ExcelGenerate(String path, List<Model> originalDataRes) {
this.path=path;
this.modelList=originalDataRes;
}

/**
* 生成Excel输入流
* @return
* @throws FileNotFoundException
* @throws URISyntaxException
*/
public InputStream GenerateFileStream( ) throws FileNotFoundException, URISyntaxException{

String file=path+”/test.xls”;           //excel模版文件
// 输出流
ByteArrayOutputStream fOut = null ;
InputStream input=new FileInputStream(file);
try {

//读取excel表格
HSSFWorkbook workbook = new HSSFWorkbook(input);
HSSFSheet sheet= workbook.getSheetAt(0);                      //  默认第一个表格

ExcelGenerate.log.info(“=====================”+originalDataRes.size());
for (int i = 0; i <modelList.size(); i++) {
HSSFRow rowTemp =sheet.createRow(i+1);               //i+1是因为第一行是标题
//创建单元格
rowTemp.createCell(0);
rowTemp.createCell(1);
rowTemp.createCell(2);
rowTemp.createCell(3);

//单元格样式
HSSFCellStyle style= this.getCellStyle(workbook.createCellStyle());
HSSFCell cell1=rowTemp.getCell(0);
//单元格填值
cell1.setCellStyle(style);
cell1.setCellValue(modelList.get(i).id);      //填单元格值

HSSFCell cell2=rowTemp.getCell(1);
cell2.setCellStyle(style);
cell2.setCellValue(modelList.get(i).name);

HSSFCell cell3=rowTemp.getCell(2);
cell3.setCellStyle(style);

cell3.setCellValue();

HSSFCell cellTemp=rowTemp.getCell(3);
cellTemp.setCellStyle(style);
cellTemp.setCellValue(modelList.get(i).title);
}

// 输出流
fOut = new ByteArrayOutputStream();
workbook.write(fOut);

//ExcelGenerate.log.info(value);
input=new ByteArrayInputStream(fOut.toByteArray());
fOut.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return input;
}
/**
* 设置单元格样式
* @param style
* @return
*/
private HSSFCellStyle getCellStyle(HSSFCellStyle style){

style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
return style;

}
}