jvm_第二章

jvm内存分析:

1:线程私有的虚拟机栈:每进入一个方法创建一个虚拟机栈,包括局部变量表,操作数栈,动态链接等,狭义的栈指的是局部变量表部分,局部变量表存放基本数据类型和各对象引用,这些都是编译期可知的,包括局部变量表的大小,在进入方法后创建的局部变量大小是不会改变了

2:堆,垃圾回收的主要区域

3:方法区:存放类的信息包括class对象,静态变量,常量等,运行时常量池也是方法区的一部分,Class文件的常量池存放着便衣生成的各种字面量和符号引用,这部分将在类加载后进入方法区的运行时常量池,相对于class文件具备了动态性,用得多的时string的intern()..关于intern,参见林另一篇博客:

--------------------------------------------华丽分割线------------------------------------------------------

对象的创建:

排除数组和Class对象的创建,普通对象创建过程:

1:new指令找参数定位常量池中类的符号引用,并检查该类是否加载,解析,初始化过,如果没有,则进行类的加载

2:对象内存的分配,两个方法:一是通过指针碰撞的无内存碎片方法;二是通过维护一个“”空闲列表“”来分配内存,在分配内存时会遇到多线程安全问题,hotSpot通过基于CAS的乐观锁保证更新操作的原子性

3:内存分配完成后,对分配的内存空间初始化为零值,不包括对象头,这一步骤保证了对象的实例字段在java中可以不赋初始值就可以使用

4:设置对象头,包括hashcode,锁的状态,GC分代年龄等....

5:执<init>方法,根据程序需求进行初始化

6:创建对象完成

--------------------------------------------华丽分割线------------------------------------------------------

对象的内存结构:

重点在对象头的mark word,多线程会接触到,锁的状态,对象头还有另一部分是对象的类型指针,指向方法区里的对象类型数据

+实例数据+填充区

对象的访问:

hotSpot采用直接指针的方式,即栈中的对象引用指向堆中的对象,堆中对象包括对象实例数据和对象头指向类型数据的指针

--------------------------------------------华丽分割线------------------------------------------------------

OutOfMemoryError:

解决mat插件的问题:无论通过link的方法还是将库文件跟myeclipse合并在一起,都无法解决,最后通过myeclipse的help-->install解决,建议通过这种方法安装插件

通过-Xmx和-Xms调堆参数,

通过HeapDumpOnOutOfMemoryError生成快照存储,通过mat分析是内存溢出还是内存泄漏,

通过-verbose:gc打印GC情况

public class OOMDump {

    static class oomObject{
        
    }
    public static void main(String[] args) {
        List<oomObject> list=new ArrayList<OOMDump.oomObject>();
        while(true){
            list.add(new oomObject());
        }
    }
}
View Code

--------------------------------------------华丽分割线------------------------------------------------------

StackOverFlowError

单线程下通过撑爆局部变量来栈内存溢出,一般不刻意设小栈内存够用的

public class stackoverFlowError {

    int stacklength=0;
    public void StackDeepInside(){
        stacklength++;
        StackDeepInside();
    }
    public static void main(String[] args) {
        stackoverFlowError stackoverFlowError=new stackoverFlowError();
        stackoverFlowError.StackDeepInside();
        System.out.println(stackoverFlowError.stacklength);
    }
}
View Code

多线程下每个线程分配的内存大小有限,进程分配内存有限,所以一般刻意烤炉通过减少堆内存来让出内存给栈

public class StackOOM {
    public void dosomething(){
        while(true){
            
        }
    }
 public void doStackMutiThread(){
     while (true){
         new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                dosomething();
            }
        }).start();
     }
 }
 public static void main(String[] args) {
    new StackOOM().doStackMutiThread();
}
}
View Code

--------------------------------------------华丽分割线------------------------------------------------------

方法区和运行时常量池的内存溢出:

1.6以前刻意通过String.intern()来不断创建动态字符串,从而内存溢出(需要改-XX:permSize=10M  -XX:MAxPermSize=10M)

对于

String.intern()的理解:

1.6中:string str=new string("zhu");   str==str.intern()会报false:原因是str是堆中数据,而intern()方法的执行会将第一次遇到的string实例赋值到方法区中,并返回方法区中该副本的引用,而在1.7中,intern()会返回首次遇到的实例在堆中的引用,所以1.7中上段代码为true

方法区的溢出可以创建大量的Class类填充:大量的jsp文件编译成java类有时会撑爆方法区

--------------------------------------------华丽分割线------------------------------------------------------

  

猜你喜欢

转载自www.cnblogs.com/ali-guili/p/9985043.html
今日推荐