1:指针碰撞:内存规整的情况下
2:空闲列表: 内存不规整的情况下
选择那种分配方式 是有 java堆是否规整而决定的。而java堆是否规整是否对应的垃圾回收器是否带有空间压缩整理的能力决定的。
因此当使用Serial,ParNew等带有压缩整理过程的收集器时,系统采用的分配算法是指针碰撞。既简单有高效。
当使用CMS这种基于清楚算法的收集器时,理论是就只能采用复杂的空闲列表。
线程分配缓冲区如果从内存分配的角度来看,所有线程共享的java堆可以划分出多个线程私有的分配缓冲区(ThreadLocal Allocation Buffer, TLAB),以提升对象分配时的效率
3:本地线程分配缓冲:对象创建在虚拟机频繁发生,即使仅仅修改一个指指向的位置,在并发的情况下也是线程不安全的,可能正在给A对象分配内存,指针还没有来得及及时修改,对象B又同时使用了原来的指针分配内存的情况。
(1):同步锁定,JVM是采用CAS失败重试来保证操作的原子性
(2):线程隔离,把内存分配的动作按照线程划分在不同的空间中进行,即每个线程在java堆中预先分配一款小内存,成为本地线程分配缓冲。只有本地线程分配缓冲用完了以后,用新的缓冲区区时才需要同步锁定。
JVM如何判断对象可以被回收:
JVM存放着所有的对象,垃圾回收器在堆回收之前,会判断那些对象“”活着“”
就是为每一个对象添加一个引用计数器,用来统计指向当前对象的引用次数,如果当前对象存在引用的更新,那么就对这个引用计数器进行增加,一旦这个引用计数器变为0,就意味着它可以被回收了。
这种方法需要额外的内存空间来存储引用计数器,但它的原理很简单,判断效率也很高。不过主流的JVM都没有采用这种方式,因为引用计数器在处理一些复杂的循环引用或者相互依赖时,可能会出现一些不再使用但是又无法回收的内存,造成内存泄露的问题。
java通过可达性算法分析判断对象是否存活,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径成为“引用链”。如果某个对象到GC Roots之间没有任何引用链相连(也成为不可达)。就证明此对象是不可能被使用的对象。就会被回收.
那些对象可以作为GC Roots?
1、虚拟机栈中的(针栈中的本地变量表)中引用的对象,列如各个线程中被调用方法堆栈中的局部变量,临时变量等
2、元空间的静态属性引用的对象,常量引用的对象。
JAVA的不同引用方式:(是通过可达性算法来说的,来判断这个GCRoot有没有引用或者指向 这个对象,而这里的引用主要分为下面4个类型)
强引用:Object object = new Object();
弱引用:SoftRerfence()内存充足时不回收,不充足时不回收
软引用:WeakRerfence()不管内存是否充足,只要GC一运行就会回收改信用对象
虚引用:很少用,形同虚设,他的作用就是该信用对象被GC回收时触发一个系统通知
JVM里面垃圾回收针对的是 新生代,老年代。还有元空间。
不会针对方法的针栈进行回收,发放一旦执行了。针栈出栈,里面的局部变量就支持从内存中清理清理掉。
代码里创建的对象一般有两种:
一种短期存活的。迅速使用完就会被回收。
一种长期存活的。需要一直生存在java堆内存中。让后续程序不停的使用。
第一种短期存活的对象,通过新生代的S0和S1被垃圾回收15次后,进入老年代中。