从几个sample来学习JAVA堆、方法区、JAVA栈和本地方法栈
最近在看《深入理解Java虚拟机》,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构:

感觉有必要通过几个实在的例子来加深对这几个区域的了解
1)Java堆
所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示:
- 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来调节,类太多有可能撑爆永久带:
- 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
静态变量或常量也会有可能撑爆方法区:
- 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如下所示:
- 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的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:
- 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栈和本地方法栈。
从几个sample来学习JAVA堆、方法区、JAVA栈和本地方法栈的更多相关文章
- jvm:内存结构(堆、方法区、程序计数器、本地方法栈、虚拟机栈)
1.jvm内存结构 静态编译:把java源文件编译成字节码文件class,这个时候class文件以静态方式存在. 类加载器:把java字节码文件加载到内存中 方法区:将字节码放到方法区作为元数据(简单 ...
- JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存
Java 虚拟机可以看作一台抽象的计算机,如同真实的计算机,它也有自己的指令集和运行时内存区域. Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存(运行时内存区域)划分为若干个不同的数 ...
- Java虚拟机栈和本地方法栈
Java虚拟机栈的特征 线程私有 后进先出(LIFO)栈 存储栈帧,支持Java方法的调用.执行和退出 可能出现OutOfMemoryError异常和StackOverflowError异常 Java ...
- java虚拟机 jvm java堆 方法区 java栈
java堆是java应用程序最密切的内存空间.几乎所有的对象都存在堆中.java堆完全自动化管理,通过垃圾回收机制,垃圾对象会自动清理,不需要显式释放. 根据java垃圾回收机制的不同,java堆可能 ...
- java高级用法之:在JNA中将本地方法映射到JAVA代码中
目录 简介 Library Mapping Function Mapping Invocation Mapping 防止VM崩溃 性能考虑 总结 简介 不管是JNI还是JNA,最终调用的都是nativ ...
- Java虚拟机03(Java虚拟机内存模型)
根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 其实最需要Java程序员关注的是堆,栈,还有方法区,因为啊: 如果代码又问题的话,可能回出现栈溢出 然后说 ...
- 【JAVA基础】05 Java语言基础:数组
1. 数组概述和定义格式说明 为什么要有数组(容器) 为了存储同种数据类型的多个值 数组概念 数组是存储同一种数据类型多个元素的集合.也可以看成是一个容器. 数组既可以存储基本数据类型,也可以存储引用 ...
- 从sample来学习Java堆(转)
1)Java堆 所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示: public class HeapOOM { static class OOMOb ...
- JVM学习001通过实例总结Java虚拟机的运行机制
JVM学习(1)——通过实例总结Java虚拟机的运行机制-转载http://www.cnblogs.com/kubixuesheng/p/5199200.html 文章转载自:http://www.c ...
随机推荐
- 存储过程--表变量和while简单运用
1.sql创建表/*订单*/CREATE TABLE Orders ( PRIMARY KEY(Id), Id int, Name varchar(20))2.存储过程ProTestDT 1)创 ...
- WordPress插件开发记录
1.a标签在新的网页中打开内容 <a href="网址" target="_blank"></a> 2.PDO的$re ...
- [TYVJ] P1001 第K极值
第K极值 背景 Background 成成第一次模拟赛 第一道 描述 Description 给定一个长度为N(0<n<=10000)的序列,保证每一个序列中的数字a[i]是小于 ...
- ng-repeat-start ng-repeat-end 的使用
ng-repeat-start与ng-repeat-end时AngularJS(1.2.x)扩展的, 使用这两个指令可以灵活控制遍历形式. 例如: index.html <div class=& ...
- POJ 2653 Pick-up sticks(线段相交)
题意:给定n个木棍依次放下,要求最终判断没被覆盖的木棍是哪些. 思路:快速排斥以及跨立实验可以判断线段相交. #include<algorithm> #include<cstdio& ...
- centos 6.4 更新源地址
执行如下命令: mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.old vim /etc/yum.repo ...
- sql server数据建表
use edudbgoif exists(select * from sysobjects where name='department')drop table departmentcreate ta ...
- BufferedReader的ready与readLine使用,以及Premature EOF异常
我的个人主页:http://www.foreyou.net 有些人在读取服务器端返回的数据的时候,使用了BufferedReader类的ready: while(reader.ready()) { / ...
- cf486A Calculating Function
A. Calculating Function time limit per test 1 second memory limit per test 256 megabytes input stand ...
- linux 虚拟机设置IP访问外网
1 设置网络为桥接模式:(Vmware为例,安装过程中也可以设置) 选中当前的操作系统,点击虚拟机-->设置-->硬件-->网络设备器,勾选桥接模式 2 修改网络配置在命令行界面输入 ...