从几个sample来学习JAVA堆、方法区、JAVA栈和本地方法栈
2015-06-14 11:24
741 查看
最近在看《深入理解Java虚拟机》,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构:
感觉有必要通过几个实在的例子来加深对这几个区域的了解
1)Java堆
所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示:
[java] view plaincopyprint?
public class HeapOOM {
static class OOMObject{}
/**
* @param args
*/
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}
加上JVM参数-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,就能很快报出OOM:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
并且能自动生成Dump。
2)方法区
方法区是存放虚拟机加载类的相关信息,如类、静态变量和常量,大小由-XX:PermSize和-XX:MaxPermSize来调节,类太多有可能撑爆永久带:
[java] view plaincopyprint?
public class MethodAreaOOM {
static class OOMOjbect{}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
while(true){
Enhancer eh = new Enhancer();
eh.setSuperclass(OOMOjbect.class);
eh.setUseCache(false);
eh.setCallback(new MethodInterceptor(){
@Override
public Object intercept(Object arg0, Method arg1,
Object[] arg2, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
return arg3.invokeSuper(arg0, arg2);
}
});
eh.create();
}
}
}
加上永久带的JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后会报如下异常:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
静态变量或常量也会有可能撑爆方法区:
[java] view plaincopyprint?
public class ConstantOOM {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = new ArrayList<String>();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
}
同样加上JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后报如下异常:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
3)Java栈和本地方法栈
栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,栈大小由Xss来调节,方法调用层次太多会撑爆这个区域,samples如下所示:
[java] view plaincopyprint?
package com.cutesource;
public class StackOOM {
/**
* @param args
*/
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args) throws Throwable{
// TODO Auto-generated method stub
StackOOM oom = new StackOOM();
try{
oom.stackLeak();
}catch(Throwable err){
System.out.println("Stack length:" + oom.stackLength);
throw err;
}
}
}
设置JVM参数:-Xss128k,报出异常:
Exception in thread "main" java.lang.StackOverflowError
打印出Stack length:1007,这里可以看出,在我的机器上128k的栈容量能承载深度为1007的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:
[java] view plaincopyprint?
package com.cutesource;
public class StackOOM {
/**
* @param args
*/
private int stackLength = 1;
private void dontStop(){
while(true){
try{Thread.sleep(1000);}catch(Exception err){}
}
}
public void stackLeakByThread(){
while(true){
Thread t = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
dontStop();
}
});
t.start();
stackLength++;
}
}
public static void main(String[] args) throws Throwable{
// TODO Auto-generated method stub
StackOOM oom = new StackOOM();
try{
oom.stackLeakByThread();
}catch(Throwable err){
System.out.println("Stack length:" + oom.stackLength);
throw err;
}
}
}
报出异常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread
不过在windows上运行这个例子要小心,会出现系统假死的情况,有可能需要重启机器才行。
以上几个例子虽然比较简单,但能很好帮助普通的程序员更加直观的了解Java堆,方法区,Java栈和本地方法栈。
感觉有必要通过几个实在的例子来加深对这几个区域的了解
1)Java堆
所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示:
[java] view plaincopyprint?
public class HeapOOM {
static class OOMObject{}
/**
* @param args
*/
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}
public class HeapOOM { static class OOMObject{} /** * @param args */ public static void main(String[] args) { List<OOMObject> list = new ArrayList<OOMObject>(); while(true){ list.add(new OOMObject()); } } }
加上JVM参数-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,就能很快报出OOM:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
并且能自动生成Dump。
2)方法区
方法区是存放虚拟机加载类的相关信息,如类、静态变量和常量,大小由-XX:PermSize和-XX:MaxPermSize来调节,类太多有可能撑爆永久带:
[java] view plaincopyprint?
public class MethodAreaOOM {
static class OOMOjbect{}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
while(true){
Enhancer eh = new Enhancer();
eh.setSuperclass(OOMOjbect.class);
eh.setUseCache(false);
eh.setCallback(new MethodInterceptor(){
@Override
public Object intercept(Object arg0, Method arg1,
Object[] arg2, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
return arg3.invokeSuper(arg0, arg2);
}
});
eh.create();
}
}
}
public class MethodAreaOOM { static class OOMOjbect{} /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub while(true){ Enhancer eh = new Enhancer(); eh.setSuperclass(OOMOjbect.class); eh.setUseCache(false); eh.setCallback(new MethodInterceptor(){ @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { // TODO Auto-generated method stub return arg3.invokeSuper(arg0, arg2); } }); eh.create(); } } }
加上永久带的JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后会报如下异常:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
静态变量或常量也会有可能撑爆方法区:
[java] view plaincopyprint?
public class ConstantOOM {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = new ArrayList<String>();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
}
public class ConstantOOM { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub List<String> list = new ArrayList<String>(); int i=0; while(true){ list.add(String.valueOf(i++).intern()); } } }
同样加上JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后报如下异常:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
3)Java栈和本地方法栈
栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,栈大小由Xss来调节,方法调用层次太多会撑爆这个区域,samples如下所示:
[java] view plaincopyprint?
package com.cutesource;
public class StackOOM {
/**
* @param args
*/
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args) throws Throwable{
// TODO Auto-generated method stub
StackOOM oom = new StackOOM();
try{
oom.stackLeak();
}catch(Throwable err){
System.out.println("Stack length:" + oom.stackLength);
throw err;
}
}
}
package com.cutesource; public class StackOOM { /** * @param args */ private int stackLength = 1; public void stackLeak(){ stackLength++; stackLeak(); } public static void main(String[] args) throws Throwable{ // TODO Auto-generated method stub StackOOM oom = new StackOOM(); try{ oom.stackLeak(); }catch(Throwable err){ System.out.println("Stack length:" + oom.stackLength); throw err; } } }
设置JVM参数:-Xss128k,报出异常:
Exception in thread "main" java.lang.StackOverflowError
打印出Stack length:1007,这里可以看出,在我的机器上128k的栈容量能承载深度为1007的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:
[java] view plaincopyprint?
package com.cutesource;
public class StackOOM {
/**
* @param args
*/
private int stackLength = 1;
private void dontStop(){
while(true){
try{Thread.sleep(1000);}catch(Exception err){}
}
}
public void stackLeakByThread(){
while(true){
Thread t = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
dontStop();
}
});
t.start();
stackLength++;
}
}
public static void main(String[] args) throws Throwable{
// TODO Auto-generated method stub
StackOOM oom = new StackOOM();
try{
oom.stackLeakByThread();
}catch(Throwable err){
System.out.println("Stack length:" + oom.stackLength);
throw err;
}
}
}
package com.cutesource; public class StackOOM { /** * @param args */ private int stackLength = 1; private void dontStop(){ while(true){ try{Thread.sleep(1000);}catch(Exception err){} } } public void stackLeakByThread(){ while(true){ Thread t = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub dontStop(); } }); t.start(); stackLength++; } } public static void main(String[] args) throws Throwable{ // TODO Auto-generated method stub StackOOM oom = new StackOOM(); try{ oom.stackLeakByThread(); }catch(Throwable err){ System.out.println("Stack length:" + oom.stackLength); throw err; } } }
报出异常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread
不过在windows上运行这个例子要小心,会出现系统假死的情况,有可能需要重启机器才行。
以上几个例子虽然比较简单,但能很好帮助普通的程序员更加直观的了解Java堆,方法区,Java栈和本地方法栈。
相关文章推荐
- entryset,IO转换流,filefilter,的练习
- eclipse Ctrl +左键查看源代码提示找不到源
- java并发编程第四章 线程执行器(2)
- Java基础 集合框架 共性方法 迭代器 ArrayList LinkedList Vector HashSet TreeSet
- JAVA问题集锦
- Spring Security实现权限管理
- Java命名规范
- java基础 第5章 隐藏实施过程
- SpringMVC上传文件
- java并发编程第四章 线程执行器(1)
- java HotSpot 内存管理白皮书
- SpringMVC学习笔记
- Struts2 重点总结 (2)
- spring <context:component-scan>使用说明(转)
- java笔记09 继承
- 欢迎使用CSDN-markdown编辑器
- java中的自定义异常(标准)
- mongo与Java之Mapreduce
- JAVA 泛型 - Class<T>
- 冒泡排序 Java