jvm的区域划分--------
运行时数据区通常包括这几个部分:程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。
1.程序计数器:线程私有,占有空间比较小。
2.虚拟机栈:线程私有的,生命周期与线程相同,用于存贮局部变量表,操作栈,动态链接和方法,
2.1局部变量表存放了编译期可知的各种数据基本类型以及对象的引用。 定义了两种异常情况:
(1)stackoverflowError:线程请求的栈深度大于jvm。
(2)outofmemoryError:扩张无法申请到足够的内存空间。
3.本地方法栈:线程私有。
4.堆:线程共享,存放所有对象:GC区,jvm主要运作区域。
5.方法区线程共享,存放类信息,常量,静态变量,常量池。
6.直接内存,不属于数据区,不属于jvm定义的内存区域。
jvm的内存回收机制----------
1.常见的标记可用对象的算法
(1)引用计数法:引用对象时,计数器加1,当对象计数器为0时,回收该对象。
注意:当两个对象互相引用时,jvm不能回收对象。
(2)根搜索算法:从根节点出发当
eg: Ob o1=new ob();
Ob o1=new ob();
o2=o1;
此时没有引用ob2对象的指向,jvm标记ob2为可回收对象。
也就是说jvm会寻找不可达对象进行标记。
根节点包含以下五种元素:
①java栈中的对象引用;
②本地方法栈中的对象引用;
③运行时常量池的对象饮用;
④方法区中静态属性的对象引用;
⑤所有class对象。
2.常见的垃圾回收算法,jvm使用的哪种?
(1)标记清除算法。
将对象标记然后直接清楚。
缺点:清楚之后由于没经过整理,会产生很多内存碎片。
(2)复制算法:被广泛用用于新生代对象的回收。
将可用内存分为from区和to区。
to区为空的区域,当from区内存用完之后将还存活的对象复制到to区,清楚整个form区。
然后将form区和to区位置互掉,也就是说原来的form区清楚完后变为to区,而to区变form区。
回收前状态:
内存回收后:
缺点:浪费内存空间,总有一块内存是空闲的,如果存活对象比较多,就需要执行较多的复制操作,效率降低。
(3)标记--整理算法:
类似于标记-清楚算法,不同的是在第二阶段将可用对象移动到一个连续的内存空间,解决了碎片问题。
这个是标记清除算法的升级版。
(4)分代回收算法(GC使用的算法)
新生代Eden与form和to区的空间大小比例为8:1:1.
当GC发生时将Eden和form区中对象复制到to区,类似与复制算法,循环往复,每个对象都有一个存活的代数,当发生如下的情况时对象进入老年代。
①当form区的对象达到存活代数设定值,进入老年代。
②回收Eden区与from区后超出to区可容纳范围,直接将存活对象移动到老年代。
当老年代满的时候,会触发fullGC。
3.常见得垃圾回收器有哪些?有什么特点?适用于什么场景?
(1)serial收集器
适用于客户端场景
(2)parnew收集器
serial多线程,并行回收
适用于多核cpu降低延迟环境,推荐应用于服务器场景
(3)parallel收集器
与parnew类似,但可以控制程序吞吐量大小,吞吐量优先的垃圾回收器。
parallel+parallel old非常适用于服务器场景。
(4)cms收集器
为高并发,低延时而生的,采用了标记-清楚算法,因此会产生大量的内存碎片,要慎重使用
(5)G1收集器
基于并行,并发,低延时,暂停时间可控的区域化分代式垃圾回收器,放弃了堆区年轻代,老年代的划分方案。
*将堆区划分为2048个大小相同的独立的region块。
4.Gc的优化分案
主要是限制Fullgc的触发
(1)不要显式的调用system.gc();
(2)尽量减少临时对象的使用。
(3)对象不用时最好显式的置为null。
(4)尽量使用stringBuffer而不用String来累加字符串。
比如:String s1=s2+s3+s4+s5;
这条语句将会产生多个垃圾对象。
(5)能用基本类型就别用封住类型。 比如:能用int别用Integer。
(6)尽量减少静态对象变量,因为他会一直占用内存。
(7)分散独享创建或者删除的时间。
5 java即使有了gc也会出现的内存泄漏情况。
1.集合类的使用。
2.各种连接未关闭。
3.监听器的使用。