您好,欢迎访问一九零五行业门户网

java内存区域与内存溢出异常的详细介绍

java内存区域与内存溢出异常一、运行时数据区域
1.程序计数器:线程私有,用于存储当前所执行的指令位置
2.java虚拟机栈:线程私有,描叙java方法执行模型;执行方法时都会创建一个栈帧,存储局部变量,基本类型变量,引用等信息
3.java本地方法栈:线程私有,为虚拟机使用到的native方法服务
4.java堆:线程共享,是垃圾收集器的主要工作地方;存储对象实例等
5.方法区:线程共享;存储类信息,常量,静态变量等
运行时常量:存放编译时生成的各种字面量和符号引用
6.直接内存:机器的内存
二、虚拟机对象1.对象的创建先检查常量池能否定位到此类的符号引用,并检查类是否已经加载初始化,否则要先执行加载过程;
为对象分配内存:计算空间并从堆中划分一块连续或不连续的区域;使用的是cas+失败重试,避免线程安全问题(因为对象创建十分频繁,不知道当前内存有没有被分配出去)
初始化内存空间:将分配的内存空间初始化0值
设置对象基本信息:元数据、hash码、gc等
执行java的init初始化:
2.对象的内存布局对象头:存储对象的hash码、锁状态等 和 类型指针(对象所指向类的元数据)
实例数据:对象真正存储的信息
对齐填充:填充符合规则
3.对象的访问定位对象的访问,通过java栈上的reference数据,它维护了一个指向对象的引用
访问方式:句柄和直接访问
句柄:堆中维护句柄池,reference指向句柄,句柄中包含了对象实例数据和类型数据的地址信息
移动方便,直接修改句柄中的实例数据即可;开销大,多了一次指针定位
直接:reference直接指向对象地址
速度快
三、实战outofmemoryerror1.java堆溢出参数:-xms堆最小值;-xmx堆最大值;-xx:+heapdumponoutofmemoryerror出现溢出时内存快照分析
堆中存放的是对象:可以创建大量对象来实现堆溢出:heap space
2.栈溢出参数:-xss设置栈值
栈深度,可以通过无限递归增加栈深度、或创建大量线程实现
//递归来stackoverflowerpublic class javavmstacksof {private int stacklength = 1;public void stackleak(){         stacklength++;         stackleak();     }public static void main(string[] args)throws throwable{         javavmstacksof oom = new javavmstacksof();try {             oom.stackleak();         } catch(throwable e){             system.out.println(stack length: + oom.stacklength);throw e;         }     } }
3.方法区和常量池溢出参数:-xx:permsize方法区大小;-xx:maxpermsize方法区最大大小
在jdk1.6前,可以通过创建大量的string,虚拟机会复制对象放入常量池,从而溢出
在1.7及以后,不可以这样,因为虚拟机只会在常量池中保存首次出现此对象时对象的引用
方法区的溢出:方法区保存的是类的信息,通过产生大量的动态类来溢出,如spring其实也是通过动态代理产生的类
public class javamethodareaoom{public static void main(string[]args){while(true){//创建大量的动态类,动态代理oomobjectenhancer enhancer=new enhancer();             enhancer.setsuperclass(oomobject.class);             enhancer.setusecache(false);             enhancer.setcallback(new methodinterceptor(){public object intercept(object obj,method method,object[]args,methodproxy proxy)throws throwable{return proxy.invokesuper(obj,args);                 }}             );             enhancer.create();         }}static class oomobject{     } }
string.intern()是一个native方法,它的作用是:如果字符串常量池中已经包含一个等于此string对象的字符串,则返回代表池中这个字符串的string对象;否则,将此string对象包含的字符串添加到常量池中,并且返回此string对象的引用
jdk6及以前:方法区(永久代)是单独的,常量池在方法区内
jdk7:去永久代
public class runtimeconstantpooloom{public static void main(string[]args){         string str1=new stringbuilder(计算机).append(软件).tostring();         system.out.println(str1.intern()==str1);         string str2=new stringbuilder(ja).append(va).tostring();         system.out.println(str2.intern()==str2);     } }
这段代码在jdk 1.6中运行,会得到两个false,而在jdk 1.7中运行,会得到一个true和一个false。
产生差异的原因是:在jdk 1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而由stringbuilder创建的字符串实例在java堆上,所以必然不是同一个引用,将返回false。
而jdk 1.7:intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由stringbuilder创建的那个字符串实例是同一个。
对str2比较返回false是因为“java”这个字符串在执行stringbuilder.tostring()之前已经出现过,字符串常量池中已经有它的引用了,不符合“首次出现”的原则,而“计算机软件”这个字符串则是首次出现的,因此返回true
注意:1.7及以后保存的是首次出现的引用;理解上面的分析
 4.本机直接内存参数:-xx:maxdirectmemorysize直接内存大小;默认==最大堆内存
以上就是java内存区域与内存溢出异常的详细介绍的详细内容。
其它类似信息

推荐信息