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()); } } }
--------------------------------------------华丽分割线------------------------------------------------------
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); } }
多线程下每个线程分配的内存大小有限,进程分配内存有限,所以一般刻意烤炉通过减少堆内存来让出内存给栈
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(); } }
--------------------------------------------华丽分割线------------------------------------------------------
方法区和运行时常量池的内存溢出:
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类有时会撑爆方法区
--------------------------------------------华丽分割线------------------------------------------------------