中都

风习袅袅,盈水展千华,飞檐亭角清铃响。犹记当初,你回眸莞尔,一笑倾城百日香。

博客园 首页 新随笔 联系 订阅 管理
Java技术体系中所提倡的自动内存管理最终可以归结为自动化地解决了两个问题:
  • 给对象分配内存 ;
  • 回收分配给对象的内存;
一般而言,对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓存(TLAB,下面会说),将按线程优先在TLAB上分配。少数情况下也可能直接分配在老年代中。总的来说,内存分配规则并不是一层不变的,其细节取决于当前使用的是哪一种垃圾收集器组合,还有虚拟机中与内存相关的参数的设置。
 
我们知道,垃圾回收策略(选择哪种垃圾回收算法)决定了我们的堆是否规整,而堆是否规整决定了我们给新对象分配内存的策略(规整的话用指针碰撞,就是一边是空闲的空间,一边是存放对象的空间,中间拿一个指针隔开,增加对象的时候移动指针即可,而堆不规整的话使用空闲列表,就是记录空闲的位置,每次创建出一个新的对象都往空闲的、足够的地方补就是了),而不同的内存分配策略又决定了线程安全性问题(两种分配策略都有线程安全性问题),那么对于线程安全的处理一般有两种方法:
 
  1. 线程同步,就是给资源上锁,这样相当于加了synchronized关键字,对于访问此处的资源的线程,只能一个一个来,给串行化了,低效;
  2. 本地线程分配缓存(TLAB),就是事先给每个线程一块空间,每个线程创建的对象都放在自己对应的空间里面;

 

下面就来说说JVM的内存分配策略吧:
 
  • 对象优先在Eden分配,当Eden区没有足够空间进行分配时,虚拟机将发起一次MinorGC。现在的商业虚拟机一般都采用复制算法来回收新生代,将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。 当进行垃圾回收时,将Eden和Survivor中还存活的对象一次性地复制到另外一块Survivor空间上,最后处理掉Eden和刚才的Survivor空间。(HotSpot虚拟机默认Eden和Survivor的大小比例是8:1)当Survivor空间不够用时,需要依赖老年代进行分配担保。
  • 大对象直接进入老年代。所谓的大对象是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组。
  • 长期存活的对象将进入老年代。当对象在新生代中经历过一定次数(默认为15)的Minor GC后,就会被晋升到老年代中。
  • 动态对象年龄判定。为了更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。动态对象年龄判断(年龄1+年龄2+年龄n的多个年龄对象占用空间总和超过了Survivor区域的50%,此时就会把年龄n以上的对象都放入老年代);
 
需要注意的是,Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间。也就是说,垃圾收集器回收的是无任何引用的对象占据的内存空间而不是对象本身。

posted on 2021-03-30 20:09  中都  阅读(109)  评论(0)    收藏  举报
Live2D