深入理解java虚拟机学习笔记1.

时间:2023-01-02 12:22:49

工作2年,对这块,不曾了解,惭愧惭愧,后来在别人的推荐下、,买来看了看,感觉还不错。

记录下笔记吧。看了下书,在自己理解的程度下,将书上的例子,弄过来了。供以后没事的时候,再看。

如果不对,还麻烦各位同行指出来,不胜感激。

今天看的,是第二章java内存区域与内存溢出异常,自己用word模仿画了个图。

深入理解java虚拟机学习笔记1.

各数据区域功能(重要,后面的例子会讲到。s):

数据区域图中,除了方法区和堆区是线程共享区外,其他三个是线程隔离的数据区(private)

程序计数器(Program Counter Register):属于线程私有的,占用的内存空间较少,可以看成是当前线程所执行字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选择下一条,需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能需要依赖这个计数器来完成,这个区域是jvm规范中没有规定任何OutOfMemoryError情况区域

(Heap):jvm中内存占用最大的一块,是所有线程共享的一块内存区域.jvm启动时创建,存放的是所有对象实例(或数组),所有的对象实例都在这里进行动态分配,当类空间无法再扩张会抛出OutOfMemoryError异常

方法区(Method Area):与堆类似,也是各个线程共享的内存区域,主要用途,用来存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,当方法区无法满足内存分配时,也抛出OutOfMemoryError异常

 

虚拟机栈:和程序计数器一样,都属于线程私有,生命周期与线程相同,描述的是java方法执行的内存模型,每个方法执行都会创建一个栈帧,用于存储局部变量表,操作栈,动态链接,方法出口等信息,每一个方法被调用直至执行完成的过程,就对应一个栈帧在jvm stack 从入栈到出栈的过程.局部变量表存放了编译期可知的各种数据基本类型(Boolean,byte,char,short,int,float,long,double),以及对象的引用。这个区域中定义了2种异常情况,如果线程请求的栈深度大于jvm所允许的深度,将抛出*Error异常,如果jvm可以动态扩张,当扩张无法申请到足够的内存空间是会抛出OutOfMemoryError异常。(这些数据区域异常将在下面的例子都讲到)。

本地方法栈:与虚拟机栈比较相似。不再描述。

上面的写的太理论化,不形象,看下这个例子就明白了。

Java栈,java堆,java方法区,三者有何关系?请看如下代码

Object object = new Object();

Object object 这部分存储在java栈的本地变量表中,作为一个引用(reference)类型存在

new Object() 这部分存储在java堆中,形成了一块存储了Object类型所有的实例数据值的结构化内存,动态变化,长度不固定。

方法区:在java堆中,必须要找到此对象类型数据,比如,对象类型,基类,实现的接口,方法等(可不可以理解成对象的所有数据结构都存在这里?)都存放在方法区

2.关于OutOfMemoryError异常的几个例子:

Ajava堆溢出:

上面讲过,java堆是用来存储对象实例的,只要不停创建对象, gc来不及回收,为了体现效果,在eclipse jvm args 设置了最少120M和最大1024M的内存占用参数。

深入理解java虚拟机学习笔记1.

 1 import java.util.ArrayList;
2 import java.util.List;
3
4 public class TestHeapOOM {
5 /**
6 * vm args -Xmn120M -Xmx1024M
7 */
8 public static void main(String[] args) {
9 List<String> list = new ArrayList<String>();
10 while(true){
11 list.add("sss");
12 }
13 }
14 }

  

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    at java.util.Arrays.copyOf(Unknown Source)

总结:java OutOfMemoryError异常,如果出现内存溢出,除了有java.lang.OutOfMemoryError,后面来还有java heap space提示信息。

当然,堆还有一种内存泄露,与内存溢出不同的是,这可能会是垃圾收集器无法自动回收造成的,这种情况要通过分析工具,具体分析才能定位。

2.jvm栈和本地方法栈的溢出

看这个前,请重新看下各数据区域功能jvm栈和本地方法栈的描述。

看完描述,结合代码来说明。

A*Error例子,需要设置的参数-Xss

深入理解java虚拟机学习笔记1.

/**
* jvm args -Xss10M
*/
public class TestStackSOF {

public long stackLenth = 1;

public void stackSOF(){
stackLenth
++;
stackSOF();
}
public static void main(String[] args) {
TestStackSOF tss
= new TestStackSOF();
try{
tss.stackSOF();
}
catch(Throwable e){
System.out.println(
"stackLenth: "+tss.stackLenth);
try {
throw e;
}
catch (Throwable e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}

  

执行的结果:

stackLenth: 326323

java.lang.*Error

    at com.cn.TestStackSOF.stackSOF(TestStackSOF.java:9)

    at com.cn.TestStackSOF.stackSOF(TestStackSOF.java:9)

如果把-Xss调到50M,执行的结果是:

stackLenth: 1637043

java.lang.*Error

    at com.cn.TestStackSOF.stackSOF(TestStackSOF.java:9)

    at com.cn.TestStackSOF.stackSOF(TestStackSOF.java:9)

总结:不难看出,-Xss大小不一样,执行的结果也不一样。如果以后在项目中遇到

java.lang.*Error异常,可以先检查代码是否有无限递归,如果不是,

可加大-Xss大小再看运行效果

方法区溢出:解题用动态代理产生大量的类,jvm args设置的参数

–XXPermSize=10M –XX:MaxPermSize=10M

(代码,有时间再补上。)