jvm内存自动管理机制
对象的创建
java堆在分配内存的时候,主要有2种方式:
1.指针碰撞

将已经使用的内存放一块,未使用的放一块.新增对象的时候,指针移动一个对象大小的距离.
2.空闲列表
新增一个列表,记录着堆中的内存块,哪些是可用的,哪些是不可用的.
区别:
指针碰撞实现相对简单,执行效率高.但是需要内存时规整的.Serial和ParNew收集器带有内存压缩整理功能.因此使用指针碰撞效果很好.
并发问题
综合上面2种方法,在并发的执行对象内存分配的时候,容易发生A对象分配内存时候,指针还没来得及修改,B对象就使用了原来的指针分配了内存.
解决:
对分配内存的动作进行同步处理,即使用cas+重试.(默认策略)
每个线程在堆中预先分配一个本地线程分配缓冲.(tlab).先在tlab中分配内存,用完了在同步方式分配.
对象的访问
1.直接指针访问,hotspot所使用的方式.

2.通过句柄访问

区别
直接指针访问,节省一次指针定位的开销,速度上稍微快些.
句柄访问时,局部变量表中存储的是句柄池的地址,对象移动时,只需要改变后面的指针,不需要改变对象的引用的地址.
垃圾回收机制
引用类型
强应用.
默认的引用.只要引用关系存在,就不会进行gc.
软引用.
当gc后,如果jvm内存不足,则会回收掉软引用.
弱引用.
不管jvm内存会不会不足,在gc的时候,都会收回弱引用.
虚引用.
主要是用来,对象在回收后,得知这个通知.
寻找GC对象
引用计数法
为对象添加一个计数器,每有一个地方引用,就+1.引用失效就-1.
问题:如果2个对象互相引用,则始终无法回收这2个对象.
可达性分析算法
由gcroots开始,根据引用关系搜索出一个引用链.这个引用链之外的对象,就是需要回收的对象.
可做为GcRoot的对象主要有如下:
a. 虚拟机栈中的栈桢的本地方法引用的对象.
b.方法区中的类静态变量.
c.方法区的常量.
d.jni使用的对象.
垃圾回收算法
标记-清除法
标记出需要回收的对象,然后再统一回收.
缺陷:
在大部分对象都需要回收的时候,需要进行大量的标记和清除动作.
清除后,造成空间碎片化.
标记-复制法
将新生代按照8:1:1的比例,划分为Eden和2个survivor区.每次只使用其中一个Eden和survivor区.需要回收的时候,将其中存活的对象复制到空闲的survivor,然后清空eden和另外一个survivor.
由于是从绝大多数需要gc的对象中挑出存活的.因此适用于新生代这一出生率高死亡率低的区域.
标记-整理法
在存活率高的老年代中,复制太多的对象,必然效率下降.在这样的区域,将存活的对象移动到一边.然后统一清除其他区域.
对象内存分配策略
1.对象优先在Eden区分配.
2.大对象直接进入老年代.
指定了-XX:PretenureSizeThreshold<字节大小>,默认值是0,大于该设置值的对象直接在老年代分配.
3.长期存活的对象直接进入老年代.
在survivor区,每进行一次minor gc,存活的对象年龄都会+1.在默认15岁后,会进入老年代.
4.动态年龄判断.
如果survivor区相同年龄的对象大于survivor一半时,会将大于或者此年龄的对象挪进老年代.
5.空间分配担保.
加入新生代survivor区无法复制进去minor gc后存活下来的对象的时候,会将放不下的对象挪进老年代.
Last updated
Was this helpful?